<?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-8172628464964340181</id><updated>2012-01-26T15:29:01.276-08:00</updated><category term='linux'/><category term='splice'/><category term='lighttpd'/><category term='pierce'/><category term='bsd sockets'/><category term='LIGHTTPD_STATIC'/><category term='commit'/><category term='transparent proxy'/><category term='nodevisitor'/><category term='socket programming'/><category term='packet socket'/><category term='parsing'/><category term='nat'/><category term='zero-copy'/><category term='daily'/><category term='git'/><category term='PACKET_TX_RING'/><category term='python'/><category term='syntax tree'/><category term='vmsplice'/><category term='email'/><category term='ast'/><category term='static libraries'/><category term='firewall'/><category term='PACKET_RX_RING'/><category term='netcat'/><title type='text'>Code Monkey Tips</title><subtitle type='html'>Code development and system administration tips for which I did not find a solution online.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8172628464964340181.post-4700845302120840979</id><published>2011-07-14T14:45:00.000-07:00</published><updated>2011-07-14T18:01:41.153-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bsd sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='vmsplice'/><category scheme='http://www.blogger.com/atom/ns#' term='zero-copy'/><category scheme='http://www.blogger.com/atom/ns#' term='splice'/><title type='text'>Zero-copy network transmission with vmsplice</title><content type='html'>&lt;h3&gt;&lt;a href="http://www.netstreamline.org/willemdebruijn/various/zerocopy-vmsplice.c"&gt;Download the complete sourcecode as zerocopy-vmsplice.c&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;This post completes a set that also includes asynchronous reading with PACKET_RX_RING and asynchronous writing with PACKET_TX_RING. In this post, we look at sending packets out over a raw socket in zero-copy fashion.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;First, understand that the presented code is a &lt;b&gt;silly hack&lt;/b&gt;: it requires four system calls for each transmitted packet, so will never be fast. I post it here because the code can be helpful in other situations where you want to use vmsplice. &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Second, note that splice support is a protocol-specific feature. Raw sockets support it as of recent kernels. I believe 2.6.36 has it, but would not be surprised if it is lacking in 2.6.34, for instance (please leave a comment if you know when it was introduced).&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The basic idea is to send data to a network socket without copying using vmsplice(). But, the vmsplice syscall will only splice into a pipe, not a network socket. Thus, the data first has to be appended to a pipe and then has to be moved to the socket using a splice() call. One extra complication is that vmsplice() works on entire pages (as it relies on memory protection mechanisms). In this example, we transport a single packet per page, which mean that we have to flush the rest of the page contents to /dev/null. It is not impossible to fill a page with multiple packets and then splice() them to the network -- this indeed sounds much more worthwhile. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;On to the code. I lifted this code from another project which always stored one packet per page, not necessarily page-aligned. That is most definitely not a requirement of splicing. In general, try to align pack multiple packets in a page and have the first be page aligned.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;/// transmit a packet using splice&lt;br /&gt;static int&lt;br /&gt;do_transmit(void *page, int pkt_offset, int pktlen)&lt;br /&gt;{&lt;br /&gt;  struct iovec iov[1];&lt;br /&gt;  int ret, len_tail;&lt;br /&gt;&lt;br /&gt;  // send page to kernel pipe&lt;br /&gt;  iov[0].iov_base = page;&lt;br /&gt;  iov[0].iov_len = getpagesize();&lt;br /&gt;&lt;br /&gt;  ret = vmsplice(tx_splicefd[1], iov, 1, SPLICE_F_GIFT);&lt;br /&gt;  if (ret != getpagesize()) {&lt;br /&gt;    fprintf(stderr, "vmsplice()\n");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // splice unused headspace to /dev/null (because our packet is not aligned)&lt;br /&gt;  ret = splice(tx_splicefd[0], NULL, tx_nullfd, NULL, pkt_offset, SPLICE_F_MOVE);&lt;br /&gt;  if (ret != pkt_offset) {&lt;br /&gt;    fprintf(stderr, "splice() header\n");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // splice or sendfile packet to tx socket&lt;br /&gt;  ret = splice(tx_splicefd[0], NULL, tx_rawsockfd, NULL, pktlen, SPLICE_F_MOVE);&lt;br /&gt;  if (ret != pktlen) {&lt;br /&gt;    fprintf(stderr, "splice() main\n");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // splice unused tailspace to /dev/null&lt;br /&gt;  len_tail = getpagesize() - pktlen - pkt_offset;&lt;br /&gt;  ret = splice(tx_splicefd[0], NULL, tx_nullfd, NULL, len_tail, SPLICE_F_MOVE);&lt;br /&gt;  if (ret != len_tail) {&lt;br /&gt;    fprintf(stderr, "splice() footer\n");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This code makes use of one pipe and two other file descriptors. tx_splicefd is a regular pipe, tx_nullfd is an open file handle to /dev/null and tx_rawsockfd is a raw IP socket. They were created as follows:&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;/// source IP address in host byte order&lt;br /&gt;#define CONF_TXHOST_HBO ((127 &lt;&lt; 1)) + 1&lt;br /&gt;&lt;br /&gt;static int tx_splicefd[2], tx_nullfd, tx_rawsockfd;&lt;br /&gt;&lt;br /&gt;/// open a RAW or UDP socket for retransmission&lt;br /&gt;//  @return 0 on success, -1 on failure&lt;br /&gt;static int&lt;br /&gt;do_init(void)&lt;br /&gt;{&lt;br /&gt;  struct sockaddr_in saddr;&lt;br /&gt;&lt;br /&gt;  // open tx socket&lt;br /&gt;  tx_rawsockfd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);&lt;br /&gt;  if (tx_rawsockfd &lt; 0) {&lt;br /&gt;    perror("socket() tx");&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // configure raw socket&lt;br /&gt;  memset(&amp;saddr, 0, sizeof(saddr));&lt;br /&gt;  saddr.sin_family      = AF_INET;&lt;br /&gt;  saddr.sin_port        = htons(ETH_P_IP);&lt;br /&gt;  saddr.sin_addr.s_addr = htonl(CONF_TXHOST_HBO);&lt;br /&gt;&lt;br /&gt;  if (connect(tx_rawsockfd, &amp;saddr, sizeof(saddr))) {&lt;br /&gt;    perror("connect() tx");&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // when splicing, have to first send to kernel pipe, then to tx socket.&lt;br /&gt;  // also, unwanted data must be flushed to /dev/null&lt;br /&gt;  // create pipe to splice to kernel&lt;br /&gt;  if (pipe(tx_splicefd)) {&lt;br /&gt;    perror("pipe() tx");&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // open /dev/null for splicing trash&lt;br /&gt;  tx_nullfd = open("/dev/null", O_WRONLY);&lt;br /&gt;  if (tx_nullfd &lt; 0) {&lt;br /&gt;    perror("open() /dev/null");&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&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/8172628464964340181-4700845302120840979?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/4700845302120840979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/zero-copy-network-transmission-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4700845302120840979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4700845302120840979'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/zero-copy-network-transmission-with.html' title='Zero-copy network transmission with vmsplice'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-6179209251578121795</id><published>2011-07-14T14:17:00.000-07:00</published><updated>2011-07-14T18:00:06.029-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='packet socket'/><category scheme='http://www.blogger.com/atom/ns#' term='PACKET_TX_RING'/><title type='text'>Asynchronous packet socket writing with PACKET_TX_RING</title><content type='html'>&lt;h3&gt;&lt;a href="http://www.netstreamline.org/willemdebruijn/various/packet-tx-ring.c"&gt;Download the complete sourcecode as packet-tx-ring.c&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;In my last post, I showed how you can read packets enqueued on a packet socket without system calls, by setting up a memory mapped ring buffer between kernel and userspace. Since version 2.6.31, the kernel also supports a transmission ring (or at least, the macro exists since that version; I tested this code against version 2.6.36).&lt;br /&gt;&lt;br /&gt;Setting up of a transmission ring is trivial once you know how to create a reception ring. In the setup snippet of the previous post, simply change the call to init_packet_sock to read&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;  fd = init_packetsock(&amp;ring, PACKET_TX_RING);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, at runtime, write packets as follows:&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;/// transmit a packet using packet ring&lt;br /&gt;//  NOTE: for high rate processing try to batch system calls, &lt;br /&gt;//        by writing multiple packets to the ring before calling send()&lt;br /&gt;//&lt;br /&gt;//  @param pkt is a packet from the network layer up (e.g., IP)&lt;br /&gt;//  @return 0 on success, -1 on failure&lt;br /&gt;static int&lt;br /&gt;process_tx(int fd, char *ring, const char *pkt, int pktlen)&lt;br /&gt;{&lt;br /&gt;  static int ring_offset = 0;&lt;br /&gt;&lt;br /&gt;  struct tpacket_hdr *header;&lt;br /&gt;  struct pollfd pollset;&lt;br /&gt;  char *off;&lt;br /&gt;  int ret;&lt;br /&gt;&lt;br /&gt;  // fetch a frame&lt;br /&gt;  // like in the PACKET_RX_RING case, we define frames to be a page long,&lt;br /&gt;  // including their header. This explains the use of getpagesize().&lt;br /&gt;  header = (void *) ring + (ring_offset * getpagesize());&lt;br /&gt;  assert((((unsigned long) header) &amp; (getpagesize() - 1)) == 0);&lt;br /&gt;  while (header-&gt;tp_status != TP_STATUS_AVAILABLE) {&lt;br /&gt;&lt;br /&gt;    // if none available: wait on more data&lt;br /&gt;    pollset.fd = fd;&lt;br /&gt;    pollset.events = POLLOUT;&lt;br /&gt;    pollset.revents = 0;&lt;br /&gt;    ret = poll(&amp;pollset, 1, 1000 /* don't hang */);&lt;br /&gt;    if (ret &lt; 0) {&lt;br /&gt;      if (errno != EINTR) {&lt;br /&gt;        perror("poll");&lt;br /&gt;        return -1;&lt;br /&gt;      }&lt;br /&gt;      return 0;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // fill data&lt;br /&gt;  off = ((void *) header) + (TPACKET_HDRLEN - sizeof(struct sockaddr_ll));&lt;br /&gt;  memcpy(off, pkt, pktlen);&lt;br /&gt;&lt;br /&gt;  // fill header&lt;br /&gt;  header-&gt;tp_len = pktlen;&lt;br /&gt;  header-&gt;tp_status = TP_STATUS_SEND_REQUEST;&lt;br /&gt;&lt;br /&gt;  // increase consumer ring pointer&lt;br /&gt;  ring_offset = (ring_offset + 1) &amp; (CONF_RING_FRAMES - 1);&lt;br /&gt;&lt;br /&gt;  // notify kernel&lt;br /&gt;  if (sendto(fd, NULL, 0, 0, (void *) &amp;txring_daddr, sizeof(txring_daddr)) &lt; 0) {&lt;br /&gt;    perror("sendto");&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;As the function comment says, this example makes inefficient use of the ring, because it issues a send() call for every packet that it writes. The whole purpose of the ring is to transmit multiple packet without having to issue a system call (and cause a kernel-mode switch).&lt;p&gt;The function also makes use of global variable txring_daddr that has not yet been introduced. Packets are copied to the Tx ring from the network layer up. This destination address structure contains the link layer information that the kernel needs to complete the packet. I do not know why we cannot just write packets from the link layer up, but this works. The following snippet sets up a destination address structure. It fills in the destination link layer as ff.ff.ff.ff.ff.ff. Replace this with a sane address in your code.&lt;/p&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;static struct sockaddr_ll txring_daddr;&lt;br /&gt;&lt;br /&gt;/// create a linklayer destination address&lt;br /&gt;//  @param ringdev is a link layer device name, such as "eth0"&lt;br /&gt;static int&lt;br /&gt;init_ring_daddr(const char *ringdev)&lt;br /&gt;{&lt;br /&gt;    struct ifreq ifreq;&lt;br /&gt;&lt;br /&gt;    // get device index&lt;br /&gt;    strcpy(ifreq.ifr_name, ringdev);&lt;br /&gt;    if (ioctl(fd, SIOCGIFINDEX, &amp;ifreq)) {&lt;br /&gt;      perror("ioctl");&lt;br /&gt;      return -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    txring_daddr.sll_family    = AF_PACKET;&lt;br /&gt;    txring_daddr.sll_protocol  = htons(ETH_P_IP);&lt;br /&gt;    txring_daddr.sll_ifindex   = ifreq.ifr_ifindex;&lt;br /&gt;&lt;br /&gt;    // set the linklayer destination address&lt;br /&gt;    // NOTE: this should be a real address, not ff.ff....&lt;br /&gt;    txring_daddr.sll_halen     = ETH_ALEN;&lt;br /&gt;    memset(&amp;txring_daddr.sll_addr, 0xff, ETH_ALEN);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The sockaddr_ll structure is defined in &amp;lt;netpacket/packet.h&amp;gt&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-6179209251578121795?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/6179209251578121795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/asynchronous-packet-socket-writing-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6179209251578121795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6179209251578121795'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/asynchronous-packet-socket-writing-with.html' title='Asynchronous packet socket writing with PACKET_TX_RING'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-6527584435735875059</id><published>2011-07-14T13:39:00.000-07:00</published><updated>2011-07-14T17:59:54.319-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PACKET_RX_RING'/><category scheme='http://www.blogger.com/atom/ns#' term='packet socket'/><title type='text'>Asynchronous packet socket reading with PACKET_RX_RING</title><content type='html'>&lt;h3&gt;&lt;a href="http://www.netstreamline.org/willemdebruijn/various/packet-rx-ring.c"&gt;Download the complete sourcecode as packet-rx-ring.c&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Since Linux 2.6.2x, processes can read network packets asynchronously using a packet socket ring buffer. By setting the socket option SOL_SOCKET PACKET_RX_RING on a packet socket, the kernel allocates a ring buffer to hold packets. It will then copy all packets that a caller would have had to read using read() to this ring buffer. The caller then maps the ring into its virtual memory by executing an mmap() call on the packet socket and from then on can read packets without issuing any system calls. It signals the kernel that it has finished processing a packet by setting a value in a header structure that is prefixed to the packet. If the caller has processed all outstanding packets, it can block by isssuing a select() involving the packet socket. &lt;br /&gt;&lt;br /&gt;This snippet shows how to set up a packet socket with ring&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;assert.h&amp;gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;#include &amp;lt;poll.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;arpa/inet.h&amp;gt;&lt;br /&gt;#include &amp;lt;netinet/if_ether.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;linux/if_packet.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/// The number of frames in the ring&lt;br /&gt;//  This number is not set in stone. Nor are block_size, block_nr or frame_size&lt;br /&gt;#define CONF_RING_FRAMES          128&lt;br /&gt;&lt;br /&gt;/// Offset of data from start of frame&lt;br /&gt;#define PKT_OFFSET      (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + \&lt;br /&gt;                         TPACKET_ALIGN(sizeof(struct sockaddr_ll)))&lt;br /&gt;&lt;br /&gt;/// (unimportant) macro for loud failure&lt;br /&gt;#define RETURN_ERROR(lvl, msg) \&lt;br /&gt;  do {                    \&lt;br /&gt;    fprintf(stderr, msg); \&lt;br /&gt;    return lvl;            \&lt;br /&gt;  } while(0);&lt;br /&gt;&lt;br /&gt;/// Initialize a packet socket ring buffer&lt;br /&gt;//  @param ringtype is one of PACKET_RX_RING or PACKET_TX_RING&lt;br /&gt;static char *&lt;br /&gt;init_packetsock_ring(int fd, int ringtype)&lt;br /&gt;{&lt;br /&gt;  struct tpacket_req tp;&lt;br /&gt;  char *ring;&lt;br /&gt;&lt;br /&gt;  // tell kernel to export data through mmap()ped ring&lt;br /&gt;  tp.tp_block_size = CONF_RING_FRAMES * getpagesize();&lt;br /&gt;  tp.tp_block_nr = 1;&lt;br /&gt;  tp.tp_frame_size = getpagesize();&lt;br /&gt;  tp.tp_frame_nr = CONF_RING_FRAMES;&lt;br /&gt;  if (setsockopt(fd, SOL_PACKET, ringtype, (void*) &amp;tp, sizeof(tp)))&lt;br /&gt;    RETURN_ERROR(NULL, "setsockopt() ring\n");&lt;br /&gt;&lt;br /&gt;#ifdef TPACKET_V2&lt;br /&gt;  val = TPACKET_V1;&lt;br /&gt;  setsockopt(fd, SOL_PACKET, PACKET_HDRLEN, &amp;val, sizeof(val));&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;  // open ring&lt;br /&gt;  ring = mmap(0, tp.tp_block_size * tp.tp_block_nr,&lt;br /&gt;               PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;  if (!ring)&lt;br /&gt;    RETURN_ERROR(NULL, "mmap()\n");&lt;br /&gt;&lt;br /&gt;  return ring;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// Create a packet socket. If param ring is not NULL, the buffer is mapped&lt;br /&gt;//  @param ring will, if set, point to the mapped ring on return&lt;br /&gt;//  @return the socket fd&lt;br /&gt;static int&lt;br /&gt;init_packetsock(char **ring, int ringtype)&lt;br /&gt;{&lt;br /&gt;  int fd;&lt;br /&gt;&lt;br /&gt;  // open packet socket&lt;br /&gt;  fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));&lt;br /&gt;  if (fd &lt; 0)&lt;br /&gt;    RETURN_ERROR(-1, "Root priliveges are required\nsocket() rx. \n");&lt;br /&gt;&lt;br /&gt;  if (ring) {&lt;br /&gt;    *ring = init_packetsock_ring(fd, ringtype);&lt;br /&gt;&lt;br /&gt;    if (!*ring) {&lt;br /&gt;      close(fd);&lt;br /&gt;      return -1;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return fd;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int&lt;br /&gt;exit_packetsock(int fd, char *ring)&lt;br /&gt;{&lt;br /&gt;  if (munmap(ring, CONF_RING_FRAMES * getpagesize())) {&lt;br /&gt;    perror("munmap");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if (close(fd)) {&lt;br /&gt;    perror("close");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// Example application that opens a packet socket with rx_ring&lt;br /&gt;int&lt;br /&gt;init_main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;  char *ring;&lt;br /&gt;  int fd;&lt;br /&gt;&lt;br /&gt;  fd = init_packetsock(&amp;ring, PACKET_RX_RING);&lt;br /&gt;  if (fd &lt; 0)&lt;br /&gt;    return 1;&lt;br /&gt;&lt;br /&gt;  // TODO: add processing. See next snippet.&lt;br /&gt;&lt;br /&gt;  if (exit_packetsock(fd, ring))&lt;br /&gt;    return 1;&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This snippet shows how to process packets at runtime using the packet ring. The firstfunction reads a single packet from the ring, the second updates the header in the ring to release the frame back to the kernel.&lt;pre&gt;&amp;nbsp;&lt;br /&gt;static int rxring_offset;&lt;br /&gt;&lt;br /&gt;/// Blocking read, returns a single packet (from packet ring)&lt;br /&gt;static void *&lt;br /&gt;process_rx(const int fd, char *rx_ring)&lt;br /&gt;{&lt;br /&gt;  struct tpacket_hdr *header;&lt;br /&gt;  struct pollfd pollset;&lt;br /&gt;  int ret;&lt;br /&gt;&lt;br /&gt;  // fetch a frame&lt;br /&gt;  header = (void *) rx_ring + (rxring_offset * getpagesize());&lt;br /&gt;  assert((((unsigned long) header) &amp; (getpagesize() - 1)) == 0);&lt;br /&gt;&lt;br /&gt;  // TP_STATUS_USER means that the process owns the packet.&lt;br /&gt;  // When a slot does not have this flag set, the frame is not&lt;br /&gt;  // ready for consumption.&lt;br /&gt;  while (!(header-&gt;tp_status &amp; TP_STATUS_USER)) {&lt;br /&gt;&lt;br /&gt;    // if none available: wait on more data&lt;br /&gt;    pollset.fd = fd;&lt;br /&gt;    pollset.events = POLLIN;&lt;br /&gt;    pollset.revents = 0;&lt;br /&gt;    ret = poll(&amp;pollset, 1, -1 /* negative means infinite */);&lt;br /&gt;    if (ret &lt; 0) {&lt;br /&gt;      if (errno != EINTR)&lt;br /&gt;        RETURN_ERROR(NULL, "poll()\n");&lt;br /&gt;      return NULL;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // check data&lt;br /&gt;  if (header-&gt;tp_status &amp; TP_STATUS_COPY)&lt;br /&gt;    RETURN_ERROR(NULL, "skipped: incomplete packed\n");&lt;br /&gt;  if (header-&gt;tp_status &amp; TP_STATUS_LOSING)&lt;br /&gt;    fprintf(stderr, "dropped packets detected\n");&lt;br /&gt;&lt;br /&gt;  // return encapsulated packet&lt;br /&gt;  return ((void *) header) + PKT_OFFSET;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Release the slot back to the kernel&lt;br /&gt;static void&lt;br /&gt;process_rx_release(char *rx_ring)&lt;br /&gt;{&lt;br /&gt;  struct tpacket_hdr *header;&lt;br /&gt;&lt;br /&gt;  // clear status to grant to kernel&lt;br /&gt;  header = (void *) rx_ring + (rxring_offset * getpagesize());&lt;br /&gt;  header-&gt;tp_status = 0;&lt;br /&gt;&lt;br /&gt;  // update consumer pointer&lt;br /&gt;  rxring_offset = (rxring_offset + 1) &amp; (CONF_RING_FRAMES - 1);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This code was copied from a project that required two separate functions. In most cases, you want to read, process and release a frame in a single loop. I'm not particularly proud of using a global variable for the current ring offset.Download the complete sourcecode as &lt;a href="http://www.netstreamline.org/willemdebruijn/various/packet-rx-ring.c"&gt;packet-rx-ring.c&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-6527584435735875059?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/6527584435735875059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/asynchronous-packet-socket-reading-with.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6527584435735875059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6527584435735875059'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/asynchronous-packet-socket-reading-with.html' title='Asynchronous packet socket reading with PACKET_RX_RING'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-4970197947105734112</id><published>2011-07-13T14:34:00.000-07:00</published><updated>2011-07-13T14:46:22.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bsd sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='socket programming'/><category scheme='http://www.blogger.com/atom/ns#' term='transparent proxy'/><title type='text'>HOWTO: bind to a non local address (transparent proxy)</title><content type='html'>In certain situations, you may want to send packets as if they're coming from a different computer. Linux prevents such IP address spoofing by default, because the most well known use is as a malicious &lt;a href="http://en.wikipedia.org/wiki/Spoofing_attack"&gt;spoofing attack&lt;/a&gt;. Still, there are legitimate reasons. For instance, a &lt;a href="http://en.wikipedia.org/wiki/Proxy_server#Transparent_proxies"&gt;transparent proxy&lt;/a&gt; intercepts traffic and replies in name of the original destination. Especially with larger sites, it is common to setup a virtual destination address and have a set of servers handle the load by mimicking this virtual host.&lt;br /&gt;&lt;br /&gt;In Linux 2.6+, to spoof packets in IPv4, bind an INET socket to a non-local address, as in this straightforward example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;#include &amp;lt;netinet/in.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define SPOOFPORT  80                // really, whichever you want&lt;br /&gt;#define SPOOFADDR  ((214 &lt;&lt; 24) + 1) // address to impersonate&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;  struct sockaddr_in spoofaddr;&lt;br /&gt;  int fd;&lt;br /&gt;&lt;br /&gt;  fd = socket(PF_INET, SOCK_DGRAM, 0);&lt;br /&gt;  if (fd == -1) {&lt;br /&gt;    perror("socket");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  memset(&amp;spoofaddr, 0, sizeof(spoofaddr));&lt;br /&gt;  spoofaddr.sin_family      = AF_INET;&lt;br /&gt;  spoofaddr.sin_port        = htons(SPOOFPORT);&lt;br /&gt;  spoofaddr.sin_addr.s_addr = htonl(SPOOFADDR);&lt;br /&gt;  if (bind(fd, (void*) &amp;spoofaddr, sizeof(spoofaddr))) {&lt;br /&gt;    perror("bind");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if (close(fd)) {&lt;br /&gt;    perror("close");&lt;br /&gt;    return 1;&lt;br /&gt;  }&lt;br /&gt;  printf("OK\n");&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;When executed on most platforms, this piece of code will print&lt;pre&gt;bind: Cannot assign requested address&lt;br /&gt;&lt;/pre&gt;To enable transparent proxy support in bind, two prerequisites must be met: (1) the application must have the &lt;tt&gt;CAP_NET_ADMIN&lt;/tt&gt; capability and (2) the host must allow transparent proxying. The easiest way to enable the first is to start with superuser privileges. Obviously, drop these privileges as soon as they are no longer needed. The second setting is configured through a &lt;tt&gt;procsfs&lt;/tt&gt;. Make sure that &lt;tt&gt;/proc/sys/net/ipv4/ip_nonlocal_bind&lt;/tt&gt; is set to &lt;tt&gt;1&lt;/tt&gt;. &lt;br /&gt;&lt;br /&gt;Now, the code should execute succesfully and you can send to any host while masquerading as coming from the Department of Defense. Yes, that's the owner of 214.x.x.x. May want to change that macro.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-4970197947105734112?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/4970197947105734112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/howto-bind-to-non-local-address.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4970197947105734112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4970197947105734112'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2011/07/howto-bind-to-non-local-address.html' title='HOWTO: bind to a non local address (transparent proxy)'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-2720436853105943680</id><published>2011-01-27T05:01:00.000-08:00</published><updated>2011-01-27T05:05:30.939-08:00</updated><title type='text'>HOWTO: Enable console autologin on Ubuntu</title><content type='html'>&lt;p&gt;This entry explains how you can automatically login to your Ubuntu machine. &lt;i&gt;Warning: the following is a &lt;b&gt;security hazard&lt;/b&gt; on network attached and publicly accessible machines&lt;/i&gt;. &lt;br /&gt;On throwaway development boxes, on the other hand, you sometimes need to reboot often and want to skip the annoying login. Only use this on inherently private machines: those that are physically secure and disconnected from the internet.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Traditional Linux&lt;/h3&gt;&lt;p&gt;On traditionally configured linux machines, download mingetty from &lt;a href="http://sourceforge.net/projects/mingetty/"&gt;sourceforge&lt;/a&gt;, compile and install it and then edit &lt;tt&gt;/etc/inittab&lt;/tt&gt;. For each console, replace lines such as&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;1:1:respawn:/etc/getty 9600 tty&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;with&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;1:1:respawn:/sbin/mingetty --autologin USERNAME tty1&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To be automatically presented with a logged-in console on boot, also disable your graphical login managers. These are usually active on console 7.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Ubuntu&lt;/h3&gt;&lt;p&gt;Ubuntu sometimes deviates from standard practice; the boot process is one example. First, to install mingetty, just run&lt;/p&gt;&lt;pre&gt;sudo apt-get install mingetty&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Ubuntu 9.04 inittab&lt;/h4&gt;&lt;p&gt;Then, update the replacement of inittab. On Ubuntu 9.04, this file is replaced by a series of files in &lt;tt&gt;/etc/event.d&lt;/tt&gt;. To automatically login on console &lt;tt&gt;tty1&lt;/tt&gt;, edit &lt;tt&gt;/etc/event.d/tty1&lt;/tt&gt;. Replace the use of &lt;tt&gt;getty&lt;/tt&gt; in the last line from&lt;/p&gt;&lt;pre&gt;exec /sbin/getty 38400 tty1&lt;/pre&gt;&lt;p&gt;to&lt;/p&gt;&lt;pre&gt;exec /sbin/mingetty --autologin USERNAME tty1&lt;/pre&gt;&lt;p&gt;To automatically login on other consoles, be sure to replace tty1 with the correct name of the console.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Ubuntu 10.04 inittab&lt;/h4&gt;&lt;p&gt;Ubuntu also changes its init process occasionally. In 10.04, the file &lt;tt&gt;/etc/event.d/tty1&lt;/tt&gt; is replaced by &lt;tt&gt;/etc/init/tty1.conf&lt;/tt&gt;. The changes are similar to those explained above.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-2720436853105943680?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/2720436853105943680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2011/01/howto-enable-console-autologin-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/2720436853105943680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/2720436853105943680'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2011/01/howto-enable-console-autologin-on.html' title='HOWTO: Enable console autologin on Ubuntu'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-1979650482114930344</id><published>2010-08-28T16:17:00.000-07:00</published><updated>2010-08-29T11:00:10.828-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='syntax tree'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='ast'/><category scheme='http://www.blogger.com/atom/ns#' term='nodevisitor'/><title type='text'>A Simple Python NodeVisitor Example</title><content type='html'>The Python &lt;tt&gt;ast&lt;/tt&gt; module helps parsing python code into its &lt;a href="http://http://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;abstract syntax tree&lt;/a&gt; and manipulating the tree. This is immensely useful, e.g., when you want to inspect code for safety or correctness. This page walks you through a very simple example to get you up and running quickly.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;A Very Simple Parser&lt;/h2&gt;The first step to analyzing a program is parsing the textual source code into an in-memory walkable tree. Module &lt;tt&gt;ast&lt;/tt&gt; takes away the hard task of implementing a generic &lt;a href="http://en.wikipedia.org/wiki/Lexical_analysis"&gt;lexer&lt;/a&gt; and python &lt;a href="http://en.wikipedia.org/wiki/Parsing"&gt;parser&lt;/a&gt; with the function &lt;tt&gt;ast.parse()&lt;/tt&gt;. The module also takes care of walking the tree. All you have to do is implement analysis code for the type of statements you are want to analyze. To do this, you implement a class that derives from class &lt;tt&gt;ast.NodeVisitor&lt;/tt&gt; and only override the member functions that are pertinent to your analysis.&lt;br /&gt;&lt;br /&gt;NodeVisitor exposes callback member functions that the tree walker ("node visitor") calls when it encounters particular python statements, one for each type of statement in the language. For instance, &lt;tt&gt;NodeVisitor.&lt;b&gt;visit_Import&lt;/b&gt;&lt;/tt&gt; is called each time the waloker encounters an import statement.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Enough with the theory..&lt;/h4&gt;As code is often the best documentation, let's look at a parser that does one thing: print a message for each import statement&lt;br /&gt;&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;import ast&lt;br /&gt;&lt;br /&gt;class FirstParser(ast.NodeVisitor):&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        pass&lt;br /&gt;&lt;br /&gt;    def visit_Import(self, stmt_import):&lt;br /&gt;      # retrieve the name from the returned object&lt;br /&gt;      # normally, there is just a single alias&lt;br /&gt;      for alias in stmt_import.names:&lt;br /&gt;        print 'import name "%s"' % alias.name&lt;br /&gt;        print 'import object %s % alias&lt;br /&gt;&lt;br /&gt;      # allow parser to continue to parse the statement's children&lt;br /&gt;      super(FirstParser, self).generic_visit(self, stmt_import)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;For the code snippet "&lt;tt&gt;import foo&lt;/tt&gt;", this produces&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;import name "foo"&lt;br /&gt;import object &lt;_ast.alias object at 0x7f05b871a690&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;h4&gt;Implementing &lt;tt&gt;visit_..&lt;/tt&gt; Callbacks&lt;/h4&gt;You can define callbacks of the form &lt;tt&gt;visit_&amp;lt;type&amp;gt;&lt;/tt&gt; for each of the left-hand symbols and right-hand constructors defined in the &lt;a href="http://docs.python.org/library/ast.html#abstract-grammar"&gt;abstract grammar for python&lt;/a&gt;. Thus, &lt;tt&gt;visit_stmt&lt;/tt&gt; and &lt;tt&gt;visit_Import&lt;/tt&gt; are both valid callbacks. Left-hand symbols may be abstract classes that are never called directly, however. Instead, their concrete implementations listed on the right are: &lt;tt&gt;visit_stmt&lt;/tt&gt; is never called, but &lt;tt&gt;visit_Import&lt;/tt&gt; implements a concrete type of statement and will be called for all import statements.&lt;br /&gt;&lt;br /&gt;In the common case, when a node has no associated &lt;tt&gt;visit_&amp;lt;type&amp;gt;&lt;/tt&gt; member, the parser calls the member &lt;tt&gt;generic_visit&lt;/tt&gt;, which ensures that the walk recurses to the children of that node -- for which you may have a member defined, even if you did not define one for the node. When you override a member, that function is called and &lt;tt&gt;generic_visit&lt;/tt&gt; is no longer called automatically. You are responsible for ensuring that the children are called, by calling &lt;tt&gt;generic_visit&lt;/tt&gt; explicitly (unless you expressly intended to stop recursion) in your member.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Using the returned objects&lt;/h2&gt;Each callback function &lt;tt&gt;visit_&amp;lt;type&amp;gt;(self, object)&lt;/tt&gt; returns with an object of a class particular to the given type. All classes derive from the &lt;a href="http://docs.python.org/library/ast.html#ast.AST"&gt;abstract class ast.AST&lt;/a&gt;. As a result, each has a member &lt;tt&gt;_fields&lt;/tt&gt;, along with members specific to the class. The &lt;tt&gt;names&lt;/tt&gt; member shown in the first example is specific to &lt;tt&gt;visit_Import&lt;/tt&gt;, for instance. Note that this corresponds to the argument of the &lt;tt&gt;Import&lt;/tt&gt; constructor in the syntax. In general, I believe that these arguments are the class-specific members, although I could not find any definite documentation on this.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The &lt;tt&gt;_fields&lt;/tt&gt; Member&lt;/h4&gt;The following snippet gives an example of how iterating of &lt;tt&gt;_fields&lt;/tt&gt; returns all children of a node. Given the input "&lt;tt&gt;a = b + 1&lt;/tt&gt;", the member function&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;    def visit_BinOp(self, stmt_binop):&lt;br /&gt;      for child in ast.iter_fields(stmt_expr):&lt;br /&gt;        print 'child %s' % str(child)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;generates the output&lt;br /&gt;&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;  child ('left', &lt;_ast.Name object at 0x7f05b871a710&gt;) &lt;br /&gt;  child ('op', &lt;_ast.Add object at 0x7f05b8715610&gt;) &lt;br /&gt;  child ('right', &lt;_ast.Num object at 0x7f05b871a750&gt;) &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;For each child, the generator returns a tuple consisting of name and child object. A quick look at the abstract syntax grammar shows that indeed all child classes again correspond to symbols in the grammar: Name, Add and Num.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Calling the Parser&lt;/h4&gt;This brings us to the last step: how to actually pass input to the parser and generate output. Assuming you have a string containing Python code, this string is parsed into an in-memory tree and the tree walked with your callbacks using:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;code = "a = b + 5"&lt;br /&gt;tree = ast.parse(code)&lt;br /&gt;parser = FirstParser()&lt;br /&gt;parser.visit(tree)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;h4&gt;A Warning on Modifying Code&lt;/h4&gt;Tree walking is not just useful for inspecting code, you can also use it to modify the parse tree. The reference documentation (see below) is very clear on the fact that you cannot use &lt;tt&gt;NodeVisitor&lt;/tt&gt; for this purpose. Instead, derive from the &lt;tt&gt;NodeTransformer&lt;/tt&gt; class, whose members are expected to return a replacement object for each object with which they are called.&lt;br /&gt;&lt;br /&gt;&lt;h2 id="bib"&gt;Further Reading&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;The authoritative information sources is &lt;a href="http://docs.python.org/library/ast.html"&gt;the Python ast module reference&lt;/a&gt;&lt;/li&gt;&lt;li&gt;StackOverflow has a &lt;a href="http://stackoverflow.com/questions/1515357/simple-example-of-how-to-use-ast-nodevisitor"&gt;discussion with informative examples&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;Feedback&lt;/h2&gt;I wrote this mini tutorial, because I failed to find one when I first started using the ast module. That said, I'm no expert at it and not even a full-time Python programmer. If you spot errors or see room for improvement, don't hesitate to post a message.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Complete Example&lt;/h2&gt;The snippets above combine into the following example, which contains minor tweaks to avoid code duplication and improve readability:&lt;br /&gt;&lt;div style="margin : 15pt; padding : 5pt; border: solid 1pt gray"&gt;&lt;pre&gt;&amp;nbsp;&lt;br /&gt;import ast&lt;br /&gt;&lt;br /&gt;class FirstParser(ast.NodeVisitor):&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        pass&lt;br /&gt;&lt;br /&gt;    def continue(self, stmt):&lt;br /&gt;        '''Helper: parse a node's children'''&lt;br /&gt;        super(FirstParser, self).generic_visit(stmt)&lt;br /&gt;&lt;br /&gt;    def parse(self, code):&lt;br /&gt;        '''Parse text into a tree and walk the result'''  &lt;br /&gt;        tree = ast.parse(code)&lt;br /&gt;        self.visit(tree)&lt;br /&gt;&lt;br /&gt;    def visit_Import(self, stmt_import):&lt;br /&gt;        # retrieve the name from the returned object&lt;br /&gt;        # normally, there is just a single alias&lt;br /&gt;        for alias in stmt_import.names:&lt;br /&gt;            print 'import name "%s"' % alias.name&lt;br /&gt;            print 'import object %s' % alias&lt;br /&gt;&lt;br /&gt;        self.continue(stmt_binop)&lt;br /&gt;&lt;br /&gt;    def visit_BinOp(self, stmt_binop):&lt;br /&gt;        print 'expression: '&lt;br /&gt;        for child in ast.iter_fields(stmt_binop):&lt;br /&gt;            print '  child %s ' % str(child)&lt;br /&gt;&lt;br /&gt;        self.continue(stmt_binop)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;parser = FirstParser()&lt;br /&gt;parser.parse('import foo')&lt;br /&gt;parser.parse('a = b + 5')&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-1979650482114930344?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/1979650482114930344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2010/08/simple-python-nodevisitor-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/1979650482114930344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/1979650482114930344'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2010/08/simple-python-nodevisitor-example.html' title='A Simple Python NodeVisitor Example'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-2687021333218474802</id><published>2010-03-21T14:35:00.000-07:00</published><updated>2010-08-29T11:01:02.404-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nat'/><category scheme='http://www.blogger.com/atom/ns#' term='firewall'/><category scheme='http://www.blogger.com/atom/ns#' term='netcat'/><category scheme='http://www.blogger.com/atom/ns#' term='pierce'/><title type='text'>Pierce Firewall from within using netcat (e.g., for Bittorrent)</title><content type='html'>&lt;h3&gt;Opening ports in a firewall&lt;/h3&gt;&lt;p&gt;If you find yourself behind a firewall that you cannot control, you often have no open &lt;a href="http://en.wikipedia.org/wiki/TCP_and_UDP_port"&gt;network ports&lt;/a&gt; for others to contact you on. End-users generally only need this for peer to peer applications, such as Bittorrent and Skype.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Pretend to initiate an outbound connection using Netcat&lt;/h3&gt;&lt;p&gt;Each time you make an outbound connection, the firewall creates a temporary opening to allow the other side to respond (say, Google to return your search results). You can exploit this feature to run Bittorrent or other servers. Pierce the firewall with a packet that originates from your computer and from the port that you want others to later contact you on (say, 6881 for Bittorrent). The easiest is to send a packet using &lt;a href="http://en.wikipedia.org/wiki/Netcat"&gt;netcat&lt;/a&gt; Using openbsd netcat, this worked for me:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;nc -p 6881 www.google.com 80&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Don't wait for a reply, just send the request, close netcat and open your real application. Note that the port will only remain open for a limited time if there is no traffic, so another computer has to make contact with yours practically immediately. &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Limitations&lt;/h3&gt;&lt;p&gt;It should work on most of the low-end routers that ISPs give you: these simply open up a port if you use it. More secure routers will only allow data between two specific computers: yours and the host you contacted (in the example, google). Then, you cannot use the opened port to serve peer to peer traffic. In short, YMMV.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The example uses openbsd netcat. Flags differ between implementations.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;NB&lt;/h3&gt;&lt;p&gt;I was quite surprised that I couldn't find a reference to this little trick online. I tried it out and it worked for me, but let me know if you see anything wrong with it.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-2687021333218474802?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/2687021333218474802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2010/03/pierce-firewall-from-within-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/2687021333218474802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/2687021333218474802'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2010/03/pierce-firewall-from-within-using.html' title='Pierce Firewall from within using netcat (e.g., for Bittorrent)'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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-8172628464964340181.post-6081293578482228664</id><published>2010-02-09T10:18:00.000-08:00</published><updated>2010-08-29T11:01:29.716-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='static libraries'/><category scheme='http://www.blogger.com/atom/ns#' term='LIGHTTPD_STATIC'/><category scheme='http://www.blogger.com/atom/ns#' term='lighttpd'/><title type='text'>Lighttpd with static modules</title><content type='html'>&lt;p&gt;For the &lt;a href="http://www.cs.cornell.edu/People/egs/nexus/"&gt;Nexus OS&lt;/a&gt; I need a version of &lt;a href="http://www.lighttpd.net/"&gt;lighttpd&lt;/a&gt; that is statically linked. Even when you build lighty as a static library, it by defaults expects to load its modules (access, dirlisting, staticfile, cgi, ...) at runtime. The following trick makes lightly include modules in the statically linked binary. It has been tested against version 1.4.25.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;CFLAGS&lt;/h4&gt;&lt;p&gt;Compile with the debug flag -DLIGHTTPD_STATIC set. I noticed that my gcc (4.4.1) also&lt;br /&gt;complained about syntax, so I had to force gcc to interpret as the C99 standard:&lt;br /&gt;&lt;/p&gt;&lt;tt&gt;&lt;br /&gt;make CFLAGS=-DLIGHTTPD_STATIC -std=c99&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;src/Makefile.in changes&lt;/h4&gt;&lt;p&gt;In src/Makefile.in (from which configure generates src/Makefile), add the modules you want to include (say, mod_access and mod_staticfile) to all lists of input to target lighttpd. Specifically, add to am__liblightcomp_la_SOURCE_DIST, am__lighttpd_SOURCES_DIST and common_src:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;mod_access.c mod_staticfile.c&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;And also add the objects. &lt;br /&gt;To am__objects_1 and am__objects_2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;mod_access.$(OBJEXT) mod_staticfile.$(OBJEXT)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;As you see, I add the targets in total 5 times to the Makefile. That's probably&lt;br /&gt;4 times unnecessarily, but it works. Add a comment if you have created &lt;br /&gt;a shorter patch. &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;src/plugin.c changes&lt;/h4&gt;&lt;p&gt;This file contains a line &lt;tt&gt;#include "plugin-static.h"&lt;/tt&gt;, but no such header is &lt;br /&gt;generated. AFAIK this is a stale entry and no longer used. However, you can make lighty&lt;br /&gt;aware of the statically linked modules by commenting out this line and adding these &lt;br /&gt;immediately below it:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;PLUGIN_INIT(mod_access)&lt;br /&gt;PLUGIN_INIT(mod_staticfile)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Feedback&lt;/h3&gt;&lt;p&gt;As always, leave a comment if you know an easier solution. If you want to see the&lt;br /&gt;full patch, download the Nexus sources from the link at the top of this post. Note&lt;br /&gt;that it includes additional modifications to handle the fact that Nexus is only&lt;br /&gt;partially Posix complete.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-6081293578482228664?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/6081293578482228664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2010/02/lighttpd-with-static-modules.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6081293578482228664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/6081293578482228664'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2010/02/lighttpd-with-static-modules.html' title='Lighttpd with static modules'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8172628464964340181.post-4837169048610252846</id><published>2010-01-14T08:50:00.000-08:00</published><updated>2010-08-29T11:01:41.476-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='email'/><category scheme='http://www.blogger.com/atom/ns#' term='commit'/><category scheme='http://www.blogger.com/atom/ns#' term='daily'/><title type='text'>Daily git commit emails</title><content type='html'>&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; can send an email for each git push into the repository&lt;br /&gt;&lt;a href="http://www.rubick.com/blogger/one-entry?entry_id=30408"&gt;using the post-receive hook&lt;/a&gt;. I wanted to have daily messages, as&lt;br /&gt;opposed to one for each commit. The following script does that:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# duration of log (default: daily) as offset since now&lt;br /&gt;RELDATE="24 hours ago"&lt;br /&gt;&lt;br /&gt;# email recipient&lt;br /&gt;EMAIL=a@b&lt;br /&gt;&lt;br /&gt;# bare repository home&lt;br /&gt;GITROOT=/opt/git/nexus&lt;br /&gt;&lt;br /&gt;# branch&lt;br /&gt;BRANCH=refs/heads/master&lt;br /&gt;&lt;br /&gt;cd $GITROOT/hooks&lt;br /&gt;&lt;br /&gt;# the latest commit&lt;br /&gt;NEWREV=`git rev-list -n 1 HEAD`&lt;br /&gt;&lt;br /&gt;# the latest commit not to report &lt;br /&gt;OLDREV=`git rev-list -n 1 --date=relative --until="$RELDATE" HEAD`&lt;br /&gt;&lt;br /&gt;# only send an email if there are commits&lt;br /&gt;if [[ $NEWREV == $OLDREV ]]&lt;br /&gt;then&lt;br /&gt; exit 0&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;/usr/share/doc/git-core/contrib/hooks/post-receive-email \&lt;br /&gt;$BRANCH $OLDREV $NEWREV | /usr/sbin/sendmail $EMAIL&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Change the GITROOT variable to point to the root of your repository and create a daily cron job:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;crontab -e&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For instance&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;12 2 * * * /usr/sbin/git-dailylog.sh&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some assumptions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;This might only work for bare repositories. &lt;/li&gt;&lt;li&gt;sendmail in this example is taken from ssmtp, real sendmail may differ.&lt;/li&gt;&lt;li&gt;verify the location of the post-receive-email script on your system&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you know of a simpler method, let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8172628464964340181-4837169048610252846?l=codemonkeytips.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codemonkeytips.blogspot.com/feeds/4837169048610252846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codemonkeytips.blogspot.com/2010/01/daily-commit-logs-batching-git-commit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4837169048610252846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8172628464964340181/posts/default/4837169048610252846'/><link rel='alternate' type='text/html' href='http://codemonkeytips.blogspot.com/2010/01/daily-commit-logs-batching-git-commit.html' title='Daily git commit emails'/><author><name>Willem</name><uri>http://www.blogger.com/profile/12773074046169371850</uri><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></feed>
